static int IoAdapter_init(IoAdapter *self, PyObject *args, PyObject *kwds) { PyObject *addr; char aclass = 'L'; char phase = '0'; int treatment = QD_TREATMENT_ANYCAST_CLOSEST; if (!PyArg_ParseTuple(args, "OO|cci", &self->handler, &addr, &aclass, &phase, &treatment)) return -1; if (!PyCallable_Check(self->handler)) { PyErr_SetString(PyExc_TypeError, "IoAdapter.__init__ handler is not callable"); return -1; } if (treatment == QD_TREATMENT_ANYCAST_BALANCED) { PyErr_SetString(PyExc_TypeError, "IoAdapter: ANYCAST_BALANCED is not supported for in-process subscriptions"); return -1; } Py_INCREF(self->handler); self->qd = dispatch; self->core = qd_router_core(self->qd); const char *address = PyString_AsString(addr); if (!address) return -1; qd_error_clear(); self->sub = qdr_core_subscribe(self->core, address, aclass, phase, treatment, qd_io_rx_handler, self); if (qd_error_code()) { PyErr_SetString(PyExc_RuntimeError, qd_error_message()); return -1; } return 0; }
qd_error_t qd_error_py_impl(const char *file, int line) { qd_python_check_lock(); if (PyErr_Occurred()) { PyObject *type, *value, *trace; PyErr_Fetch(&type, &value, &trace); /* Note clears the python error indicator */ PyObject *py_type_name = type ? PyObject_GetAttrString(type, "__name__") : NULL; const char *type_name = py_type_name ? PyString_AsString(py_type_name) : NULL; PyObject *py_value_str = value ? PyObject_Str(value) : NULL; const char *value_str = py_value_str ? PyString_AsString(py_value_str) : NULL; if (!value_str) value_str = "Unknown"; PyErr_Clear(); /* Ignore errors while we're trying to build the values. */ if (type_name) qd_error_impl(QD_ERROR_PYTHON, file, line, "%s: %s", type_name, value_str); else qd_error_impl(QD_ERROR_PYTHON, file, line, "%s", value_str); Py_XDECREF(py_value_str); Py_XDECREF(py_type_name); log_trace_py(type, value, trace, QD_LOG_ERROR, file, line); Py_XDECREF(type); Py_XDECREF(value); Py_XDECREF(trace); } else { qd_error_clear(); } return qd_error_code(); }
qd_config_ssl_profile_t *qd_dispatch_configure_ssl_profile(qd_dispatch_t *qd, qd_entity_t *entity) { qd_error_clear(); qd_connection_manager_t *cm = qd->connection_manager; qd_config_ssl_profile_t *ssl_profile = NEW(qd_config_ssl_profile_t); DEQ_ITEM_INIT(ssl_profile); DEQ_INSERT_TAIL(cm->config_ssl_profiles, ssl_profile); ssl_profile->name = qd_entity_opt_string(entity, "name", 0); CHECK(); ssl_profile->ssl_certificate_file = qd_entity_opt_string(entity, "certFile", 0); CHECK(); ssl_profile->ssl_private_key_file = qd_entity_opt_string(entity, "keyFile", 0); CHECK(); ssl_profile->ssl_password = qd_entity_opt_string(entity, "password", 0); CHECK(); ssl_profile->ssl_trusted_certificate_db = qd_entity_opt_string(entity, "certDb", 0); CHECK(); ssl_profile->ssl_trusted_certificates = qd_entity_opt_string(entity, "trustedCerts", 0); CHECK(); ssl_profile->ssl_uid_format = qd_entity_opt_string(entity, "uidFormat", 0); CHECK(); ssl_profile->ssl_display_name_file = qd_entity_opt_string(entity, "displayNameFile", 0); CHECK(); sys_atomic_init(&ssl_profile->ref_count, 0); qd_log(cm->log_source, QD_LOG_INFO, "Created SSL Profile with name %s ", ssl_profile->name); return ssl_profile; error: qd_log(cm->log_source, QD_LOG_ERROR, "Unable to create ssl profile: %s", qd_error_message()); qd_config_ssl_profile_free(cm, ssl_profile); return 0; }
qd_config_connector_t *qd_dispatch_configure_connector(qd_dispatch_t *qd, qd_entity_t *entity) { qd_error_clear(); qd_connection_manager_t *cm = qd->connection_manager; qd_config_connector_t *cc = NEW(qd_config_connector_t); ZERO(cc); cc->is_connector = true; qd_config_ssl_profile_t *ssl_profile = 0; if (load_server_config(qd, &cc->configuration, entity, &ssl_profile) != QD_ERROR_NONE) { qd_log(cm->log_source, QD_LOG_ERROR, "Unable to create config connector: %s", qd_error_message()); qd_config_connector_free(qd->connection_manager, cc); return 0; } cc->ssl_profile = ssl_profile; DEQ_ITEM_INIT(cc); DEQ_INSERT_TAIL(cm->config_connectors, cc); qd_log(cm->log_source, QD_LOG_INFO, "Configured Connector: %s:%s proto=%s, role=%s %s%s", cc->configuration.host, cc->configuration.port, cc->configuration.protocol_family ? cc->configuration.protocol_family : "any", cc->configuration.role, cc->ssl_profile ? ", sslProfile=":"", cc->ssl_profile ? cc->ssl_profile->name:""); return cc; }
qd_config_listener_t *qd_dispatch_configure_listener(qd_dispatch_t *qd, qd_entity_t *entity) { qd_error_clear(); qd_connection_manager_t *cm = qd->connection_manager; qd_config_listener_t *cl = NEW(qd_config_listener_t); cl->is_connector = false; cl->state = QD_BIND_NONE; cl->listener = 0; qd_config_ssl_profile_t *ssl_profile = 0; if (load_server_config(qd, &cl->configuration, entity, &ssl_profile) != QD_ERROR_NONE) { qd_log(cm->log_source, QD_LOG_ERROR, "Unable to create config listener: %s", qd_error_message()); qd_config_listener_free(qd->connection_manager, cl); return 0; } cl->ssl_profile = ssl_profile; DEQ_ITEM_INIT(cl); DEQ_INSERT_TAIL(cm->config_listeners, cl); qd_log(cm->log_source, QD_LOG_INFO, "Configured Listener: %s:%s proto=%s, role=%s%s%s", cl->configuration.host, cl->configuration.port, cl->configuration.protocol_family ? cl->configuration.protocol_family : "any", cl->configuration.role, cl->ssl_profile ? ", sslProfile=":"", cl->ssl_profile ? cl->ssl_profile->name:""); return cl; }
long qd_entity_get_long(qd_entity_t *entity, const char* attribute) { qd_error_clear(); PyObject *py_obj = qd_entity_get_py(entity, attribute); long result = py_obj ? PyInt_AsLong(py_obj) : -1; Py_XDECREF(py_obj); qd_error_py(); return result; }
bool qd_entity_get_bool(qd_entity_t *entity, const char* attribute) { qd_error_clear(); PyObject *py_obj = qd_entity_get_py(entity, attribute); bool result = py_obj ? PyObject_IsTrue(py_obj) : false; Py_XDECREF(py_obj); qd_error_py(); return result; }
char *qd_entity_get_string(qd_entity_t *entity, const char* attribute) { qd_error_clear(); PyObject *py_obj = qd_entity_get_py(entity, attribute); PyObject *py_str = py_obj ? PyObject_Str(py_obj) : NULL; const char *cstr = py_str ? PyString_AsString(py_str) : NULL; char* str = cstr ? strdup(cstr) : NULL; Py_XDECREF(py_obj); Py_XDECREF(py_str); if (!str) qd_error_py(); return str; }
// Get events in the add/remove cache into a python list of (action, type, pointer) // Locks the entity cache so entities can be updated safely (prevent entities from being deleted.) // Do not processs any entities if return error code != 0 // Must call qd_entity_refresh_end when done, regardless of error code. qd_error_t qd_entity_refresh_begin(PyObject *list) { if (!event_lock) return QD_ERROR_NONE; /* Unit tests don't call qd_entity_cache_initialize */ qd_error_clear(); sys_mutex_lock(event_lock); entity_event_t *event = DEQ_HEAD(event_list); while (event) { PyObject *tuple = Py_BuildValue("(isl)", (int)event->action, event->type, (long)event->object); if (!tuple) { qd_error_py(); break; } int err = PyList_Append(list, tuple); Py_DECREF(tuple); if (err) { qd_error_py(); break; } DEQ_REMOVE_HEAD(event_list); free(event); event = DEQ_HEAD(event_list); } return qd_error_code(); }
// Copy a message field, using to_py to a python object attribute. static qd_error_t iter_to_py_attr(qd_field_iterator_t *iter, PyObject* (*to_py)(qd_field_iterator_t *), PyObject *obj, const char *attr) { qd_error_clear(); if (iter) { PyObject *value = to_py(iter); qd_field_iterator_free(iter); if (value) { PyObject_SetAttrString(obj, attr, value); Py_DECREF(value); } else { qd_error_py(); /* In case there were python errors. */ qd_error(QD_ERROR_MESSAGE, "Can't convert message field %s", attr); } } return qd_error_code(); }
qd_error_t qd_pyrouter_tick(qd_router_t *router) { qd_error_clear(); qd_error_t err = QD_ERROR_NONE; PyObject *pArgs; PyObject *pValue; if (pyTick && router->router_mode == QD_ROUTER_MODE_INTERIOR) { qd_python_lock_state_t lock_state = qd_python_lock(); pArgs = PyTuple_New(0); pValue = PyObject_CallObject(pyTick, pArgs); Py_DECREF(pArgs); Py_XDECREF(pValue); err = qd_error_py(); qd_python_unlock(lock_state); } return err; }
qd_error_t qd_error_errno_impl(int errnum, const char *file, int line, const char *fmt, ...) { if (errnum) { ts.error_code = QD_ERROR_SYSTEM; char buf[ERROR_MAX]; char *errstr = strerror_r(errno, buf, sizeof(buf)); char *begin = ts.error_message; char *end = begin + ERROR_MAX; va_list arglist; va_start(arglist, fmt); vaprintf(&begin, end, fmt, arglist); va_end(arglist); aprintf(&begin, end, ": %s", errstr); qd_log_impl(log_source, QD_LOG_ERROR, file, line, "%s", qd_error_message()); return qd_error_code(); } else return qd_error_clear(); }
static void write_log(qd_log_source_t *log_source, qd_log_entry_t *entry) { log_sink_t* sink = log_source->sink ? log_source->sink : default_log_source->sink; if (!sink) return; char log_str[LOG_MAX]; char *begin = log_str; char *end = log_str + LOG_MAX; const level_t *level = level_for_bit(entry->level); if (!level) { level = &levels[INFO]; qd_error_clear(); } if (default_bool(log_source->timestamp, default_log_source->timestamp)) { char buf[100]; buf[0] = '\0'; ctime_r(&entry->time, buf); buf[strlen(buf)-1] = '\0'; /* Get rid of trailng \n */ aprintf(&begin, end, "%s ", buf); } aprintf(&begin, end, "%s (%s) %s", entry->module, level->name, entry->text); if (default_bool(log_source->source, default_log_source->source) && entry->file) aprintf(&begin, end, " (%s:%d)", entry->file, entry->line); aprintf(&begin, end, "\n"); if (sink->file) { if (fputs(log_str, sink->file) == EOF) { char msg[TEXT_MAX]; snprintf(msg, sizeof(msg), "Cannot write log output to '%s'", sink->name); perror(msg); exit(1); }; fflush(sink->file); } if (sink->syslog) { int syslog_level = level->syslog; if (syslog_level != -1) syslog(syslog_level, "%s", log_str); } }
qd_config_sasl_plugin_t *qd_dispatch_configure_sasl_plugin(qd_dispatch_t *qd, qd_entity_t *entity) { qd_error_clear(); qd_connection_manager_t *cm = qd->connection_manager; qd_config_sasl_plugin_t *sasl_plugin = NEW(qd_config_sasl_plugin_t); DEQ_ITEM_INIT(sasl_plugin); DEQ_INSERT_TAIL(cm->config_sasl_plugins, sasl_plugin); sasl_plugin->name = qd_entity_opt_string(entity, "name", 0); CHECK(); sasl_plugin->auth_service = qd_entity_opt_string(entity, "authService", 0); CHECK(); sasl_plugin->sasl_init_hostname = qd_entity_opt_string(entity, "saslInitHostname", 0); CHECK(); sasl_plugin->auth_ssl_profile = qd_entity_opt_string(entity, "authSslProfile", 0); CHECK(); qd_log(cm->log_source, QD_LOG_INFO, "Created SASL plugin config with name %s", sasl_plugin->name); return sasl_plugin; error: qd_log(cm->log_source, QD_LOG_ERROR, "Unable to create SASL plugin config: %s", qd_error_message()); config_sasl_plugin_free(cm, sasl_plugin); return 0; }
static PyObject *qd_python_send(PyObject *self, PyObject *args) { qd_error_clear(); IoAdapter *ioa = (IoAdapter*) self; qd_composed_field_t *field = 0; PyObject *message = 0; int no_echo = 1; int control = 0; if (!PyArg_ParseTuple(args, "O|ii", &message, &no_echo, &control)) return 0; if (compose_python_message(&field, message, ioa->qd) == QD_ERROR_NONE) { qd_message_t *msg = qd_message(); qd_message_compose_2(msg, field); qd_composed_field_t *ingress = qd_compose_subfield(0); qd_compose_insert_string(ingress, qd_router_id(ioa->qd)); qd_composed_field_t *trace = qd_compose_subfield(0); qd_compose_start_list(trace); qd_compose_insert_string(trace, qd_router_id(ioa->qd)); qd_compose_end_list(trace); qd_message_set_ingress_annotation(msg, ingress); qd_message_set_trace_annotation(msg, trace); PyObject *address = PyObject_GetAttrString(message, "address"); if (address) { qdr_send_to2(ioa->core, msg, PyString_AsString(address), (bool) no_echo, (bool) control); Py_DECREF(address); } qd_compose_free(field); qd_message_free(msg); Py_RETURN_NONE; } if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError, qd_error_message()); return 0; }
qd_error_t qd_log_entity(qd_entity_t *entity) { qd_error_clear(); char* module = qd_entity_get_string(entity, "module"); QD_ERROR_RET(); sys_mutex_lock(log_source_lock); qd_log_source_t *src = qd_log_source_lh(module); /* The original log source */ free(module); qd_log_source_t copy = *src; /* A copy to modify outside the lock. */ sys_mutex_unlock(log_source_lock); if (qd_entity_has(entity, "enable")) { char *enable = qd_entity_get_string(entity, "enable"); copy.mask = enable_mask(enable); free(enable); } QD_ERROR_RET(); if (qd_entity_has(entity, "timestamp")) copy.timestamp = qd_entity_get_bool(entity, "timestamp"); QD_ERROR_RET(); if (qd_entity_has(entity, "source")) copy.source = qd_entity_get_bool(entity, "source"); QD_ERROR_RET(); if (qd_entity_has(entity, "output")) { log_sink_free_lh(copy.sink); /* DEFAULT source may already have a sink */ char* output = qd_entity_get_string(entity, "output"); QD_ERROR_RET(); copy.sink = log_sink_lh(output); free(output); if (copy.sink->syslog) /* Timestamp off for syslog. */ copy.timestamp = 0; } sys_mutex_lock(log_source_lock); *src = copy; sys_mutex_unlock(log_source_lock); return qd_error_code(); }
qd_error_t qd_error_impl(qd_error_t code, const char *file, int line, const char *fmt, ...) { ts.error_code = code; if (code) { char *begin = ts.error_message; char *end = begin + ERROR_MAX; (void)aprintf; const char* name = qd_error_name(code); if (name) aprintf(&begin, end, "%s: ", name); else aprintf(&begin, end, "%d: ", code); va_list arglist; va_start(arglist, fmt); vaprintf(&begin, end, fmt, arglist); va_end(arglist); // NOTE: Use the file/line from the qd_error macro, not this line in error.c qd_log_impl(log_source, QD_LOG_ERROR, file, line, "%s", qd_error_message()); return code; } else qd_error_clear(); return 0; }
/** * Set a value for an entity attribute. If py_value == NULL then clear the attribute. * If the attribute exists and is a list, append this value to the list. * * NOTE: This function will Py_XDECREF(py_value). */ qd_error_t qd_entity_set_py(qd_entity_t* entity, const char* attribute, PyObject* py_value) { qd_error_clear(); int result = 0; PyObject *py_key = PyString_FromString(attribute); if (py_key) { if (py_value == NULL) { /* Delete the attribute */ result = PyObject_DelItem((PyObject*)entity, py_key); PyErr_Clear(); /* Ignore error if it isn't there. */ } else { PyObject *old = PyObject_GetItem((PyObject*)entity, py_key); PyErr_Clear(); /* Ignore error if it isn't there. */ if (old && PyList_Check(old)) /* Add to list */ result = PyList_Append(old, py_value); else /* Set attribute */ result = PyObject_SetItem((PyObject*)entity, py_key, py_value); Py_XDECREF(old); } } Py_XDECREF(py_key); Py_XDECREF(py_value); return (py_key == NULL || result < 0) ? qd_error_py() : QD_ERROR_NONE; }
static bool qd_message_check_LH(qd_message_content_t *content, qd_message_depth_t depth) { qd_error_clear(); qd_buffer_t *buffer = DEQ_HEAD(content->buffers); if (!buffer) { qd_error(QD_ERROR_MESSAGE, "No data"); return false; } if (depth <= content->parse_depth) return true; // We've already parsed at least this deep if (content->parse_buffer == 0) { content->parse_buffer = buffer; content->parse_cursor = qd_buffer_base(content->parse_buffer); } if (depth == QD_DEPTH_NONE) return true; // // MESSAGE HEADER // if (0 == qd_check_field_LH(content, QD_DEPTH_HEADER, MSG_HDR_LONG, MSG_HDR_SHORT, TAGS_LIST, &content->section_message_header, 0)) { qd_error(QD_ERROR_MESSAGE, "Invalid header"); return false; } if (depth == QD_DEPTH_HEADER) return true; // // DELIVERY ANNOTATION // if (0 == qd_check_field_LH(content, QD_DEPTH_DELIVERY_ANNOTATIONS, DELIVERY_ANNOTATION_LONG, DELIVERY_ANNOTATION_SHORT, TAGS_MAP, &content->section_delivery_annotation, 0)) { qd_error(QD_ERROR_MESSAGE, "Invalid delivery-annotations"); return false; } if (depth == QD_DEPTH_DELIVERY_ANNOTATIONS) return true; // // MESSAGE ANNOTATION // if (0 == qd_check_field_LH(content, QD_DEPTH_MESSAGE_ANNOTATIONS, MESSAGE_ANNOTATION_LONG, MESSAGE_ANNOTATION_SHORT, TAGS_MAP, &content->section_message_annotation, 0)) { qd_error(QD_ERROR_MESSAGE, "Invalid annotations"); return false; } if (depth == QD_DEPTH_MESSAGE_ANNOTATIONS) return true; // // PROPERTIES // if (0 == qd_check_field_LH(content, QD_DEPTH_PROPERTIES, PROPERTIES_LONG, PROPERTIES_SHORT, TAGS_LIST, &content->section_message_properties, 0)) { qd_error(QD_ERROR_MESSAGE, "Invalid message properties"); return false; } if (depth == QD_DEPTH_PROPERTIES) return true; // // APPLICATION PROPERTIES // if (0 == qd_check_field_LH(content, QD_DEPTH_APPLICATION_PROPERTIES, APPLICATION_PROPERTIES_LONG, APPLICATION_PROPERTIES_SHORT, TAGS_MAP, &content->section_application_properties, 0)) { qd_error(QD_ERROR_MESSAGE, "Invalid application-properties"); return false; } if (depth == QD_DEPTH_APPLICATION_PROPERTIES) return true; // // BODY // Note that this function expects a limited set of types in a VALUE section. This is // not a problem for messages passing through Dispatch because through-only messages won't // be parsed to BODY-depth. // if (0 == qd_check_field_LH(content, QD_DEPTH_BODY, BODY_DATA_LONG, BODY_DATA_SHORT, TAGS_BINARY, &content->section_body, 1)) { qd_error(QD_ERROR_MESSAGE, "Invalid body data"); return false; } if (0 == qd_check_field_LH(content, QD_DEPTH_BODY, BODY_SEQUENCE_LONG, BODY_SEQUENCE_SHORT, TAGS_LIST, &content->section_body, 1)) { qd_error(QD_ERROR_MESSAGE, "Invalid body sequence"); return false; } if (0 == qd_check_field_LH(content, QD_DEPTH_BODY, BODY_VALUE_LONG, BODY_VALUE_SHORT, TAGS_ANY, &content->section_body, 0)) { qd_error(QD_ERROR_MESSAGE, "Invalid body value"); return false; } if (depth == QD_DEPTH_BODY) return true; // // FOOTER // if (0 == qd_check_field_LH(content, QD_DEPTH_ALL, FOOTER_LONG, FOOTER_SHORT, TAGS_MAP, &content->section_footer, 0)) { qd_error(QD_ERROR_MESSAGE, "Invalid footer"); return false; } return true; }
static qd_error_t load_server_config(qd_dispatch_t *qd, qd_server_config_t *config, qd_entity_t* entity, bool is_listener) { qd_error_clear(); bool authenticatePeer = qd_entity_opt_bool(entity, "authenticatePeer", false); CHECK(); bool verifyHostName = qd_entity_opt_bool(entity, "verifyHostName", true); CHECK(); bool requireEncryption = qd_entity_opt_bool(entity, "requireEncryption", false); CHECK(); bool requireSsl = qd_entity_opt_bool(entity, "requireSsl", false); CHECK(); memset(config, 0, sizeof(*config)); config->log_message = qd_entity_opt_string(entity, "logMessage", 0); CHECK(); config->log_bits = populate_log_message(config); config->port = qd_entity_get_string(entity, "port"); CHECK(); config->name = qd_entity_opt_string(entity, "name", 0); CHECK(); config->role = qd_entity_get_string(entity, "role"); CHECK(); config->inter_router_cost = qd_entity_opt_long(entity, "cost", 1); CHECK(); config->protocol_family = qd_entity_opt_string(entity, "protocolFamily", 0); CHECK(); config->http = qd_entity_opt_bool(entity, "http", false); CHECK(); config->http_root = qd_entity_opt_string(entity, "httpRoot", false); CHECK(); config->http = config->http || config->http_root; /* httpRoot implies http */ config->max_frame_size = qd_entity_get_long(entity, "maxFrameSize"); CHECK(); config->max_sessions = qd_entity_get_long(entity, "maxSessions"); CHECK(); uint64_t ssn_frames = qd_entity_opt_long(entity, "maxSessionFrames", 0); CHECK(); config->idle_timeout_seconds = qd_entity_get_long(entity, "idleTimeoutSeconds"); CHECK(); if (is_listener) { config->initial_handshake_timeout_seconds = qd_entity_get_long(entity, "initialHandshakeTimeoutSeconds"); CHECK(); } config->sasl_username = qd_entity_opt_string(entity, "saslUsername", 0); CHECK(); config->sasl_password = qd_entity_opt_string(entity, "saslPassword", 0); CHECK(); config->sasl_mechanisms = qd_entity_opt_string(entity, "saslMechanisms", 0); CHECK(); config->ssl_profile = qd_entity_opt_string(entity, "sslProfile", 0); CHECK(); config->sasl_plugin = qd_entity_opt_string(entity, "saslPlugin", 0); CHECK(); config->link_capacity = qd_entity_opt_long(entity, "linkCapacity", 0); CHECK(); config->multi_tenant = qd_entity_opt_bool(entity, "multiTenant", false); CHECK(); set_config_host(config, entity); // // Handle the defaults for various settings // if (config->link_capacity == 0) config->link_capacity = 250; if (config->max_sessions == 0 || config->max_sessions > 32768) // Proton disallows > 32768 config->max_sessions = 32768; if (config->max_frame_size < QD_AMQP_MIN_MAX_FRAME_SIZE) // Silently promote the minimum max-frame-size // Proton will do this but the number is needed for the // incoming capacity calculation. config->max_frame_size = QD_AMQP_MIN_MAX_FRAME_SIZE; // // Given session frame count and max frame size compute session incoming_capacity // if (ssn_frames == 0) config->incoming_capacity = (sizeof(size_t) < 8) ? 0x7FFFFFFFLL : 0x7FFFFFFFLL * config->max_frame_size; else { uint64_t mfs = (uint64_t) config->max_frame_size; uint64_t trial_ic = ssn_frames * mfs; uint64_t limit = (sizeof(size_t) < 8) ? (1ll << 31) - 1 : 0; if (limit == 0 || trial_ic < limit) { // Silently promote incoming capacity of zero to one config->incoming_capacity = (trial_ic < QD_AMQP_MIN_MAX_FRAME_SIZE ? QD_AMQP_MIN_MAX_FRAME_SIZE : trial_ic); } else { config->incoming_capacity = limit; uint64_t computed_ssn_frames = limit / mfs; qd_log(qd->connection_manager->log_source, QD_LOG_WARNING, "Server configuation for I/O adapter entity name:'%s', host:'%s', port:'%s', " "requested maxSessionFrames truncated from %"PRId64" to %"PRId64, config->name, config->host, config->port, ssn_frames, computed_ssn_frames); } } // // For now we are hardwiring this attribute to true. If there's an outcry from the // user community, we can revisit this later. // config->allowInsecureAuthentication = true; config->verify_host_name = verifyHostName; char *stripAnnotations = qd_entity_opt_string(entity, "stripAnnotations", 0); load_strip_annotations(config, stripAnnotations); free(stripAnnotations); stripAnnotations = 0; CHECK(); config->requireAuthentication = authenticatePeer; config->requireEncryption = requireEncryption || requireSsl; if (config->ssl_profile) { config->ssl_required = requireSsl; config->ssl_require_peer_authentication = config->sasl_mechanisms && strstr(config->sasl_mechanisms, "EXTERNAL") != 0; qd_config_ssl_profile_t *ssl_profile = qd_find_ssl_profile(qd->connection_manager, config->ssl_profile); if (ssl_profile) { config->ssl_certificate_file = SSTRDUP(ssl_profile->ssl_certificate_file); config->ssl_private_key_file = SSTRDUP(ssl_profile->ssl_private_key_file); config->ciphers = SSTRDUP(ssl_profile->ciphers); config->ssl_password = SSTRDUP(ssl_profile->ssl_password); config->ssl_trusted_certificate_db = SSTRDUP(ssl_profile->ssl_trusted_certificate_db); config->ssl_trusted_certificates = SSTRDUP(ssl_profile->ssl_trusted_certificates); config->ssl_uid_format = SSTRDUP(ssl_profile->ssl_uid_format); config->ssl_display_name_file = SSTRDUP(ssl_profile->ssl_display_name_file); } } if (config->sasl_plugin) { qd_config_sasl_plugin_t *sasl_plugin = qd_find_sasl_plugin(qd->connection_manager, config->sasl_plugin); if (sasl_plugin) { config->auth_service = SSTRDUP(sasl_plugin->auth_service); config->sasl_init_hostname = SSTRDUP(sasl_plugin->sasl_init_hostname); qd_log(qd->connection_manager->log_source, QD_LOG_INFO, "Using auth service %s from SASL Plugin %s", config->auth_service, config->sasl_plugin); if (sasl_plugin->auth_ssl_profile) { qd_config_ssl_profile_t *auth_ssl_profile = qd_find_ssl_profile(qd->connection_manager, sasl_plugin->auth_ssl_profile); config->auth_ssl_conf = pn_ssl_domain(PN_SSL_MODE_CLIENT); if (auth_ssl_profile->ssl_certificate_file) { if (pn_ssl_domain_set_credentials(config->auth_ssl_conf, auth_ssl_profile->ssl_certificate_file, auth_ssl_profile->ssl_private_key_file, auth_ssl_profile->ssl_password)) { qd_error(QD_ERROR_RUNTIME, "Cannot set SSL credentials for authentication service"); CHECK(); } } if (auth_ssl_profile->ssl_trusted_certificate_db) { if (pn_ssl_domain_set_trusted_ca_db(config->auth_ssl_conf, auth_ssl_profile->ssl_trusted_certificate_db)) { qd_error(QD_ERROR_RUNTIME, "Cannot set trusted SSL certificate db for authentication service" ); CHECK(); } else { if (pn_ssl_domain_set_peer_authentication(config->auth_ssl_conf, PN_SSL_VERIFY_PEER, auth_ssl_profile->ssl_trusted_certificate_db)) { qd_error(QD_ERROR_RUNTIME, "Cannot set SSL peer verification for authentication service"); CHECK(); } } } if (auth_ssl_profile->ciphers) { if (pn_ssl_domain_set_ciphers(config->auth_ssl_conf, auth_ssl_profile->ciphers)) { return qd_error(QD_ERROR_RUNTIME, "Cannot set ciphers. The ciphers string might be invalid. Use openssl ciphers -v <ciphers> to validate"); } } } } else { qd_error(QD_ERROR_RUNTIME, "Cannot find sasl plugin %s", config->sasl_plugin); CHECK(); } } return QD_ERROR_NONE; error: qd_server_config_free(config); return qd_error_code(); }
qd_config_ssl_profile_t *qd_dispatch_configure_ssl_profile(qd_dispatch_t *qd, qd_entity_t *entity) { qd_error_clear(); qd_connection_manager_t *cm = qd->connection_manager; qd_config_ssl_profile_t *ssl_profile = NEW(qd_config_ssl_profile_t); DEQ_ITEM_INIT(ssl_profile); DEQ_INSERT_TAIL(cm->config_ssl_profiles, ssl_profile); ssl_profile->name = qd_entity_opt_string(entity, "name", 0); CHECK(); ssl_profile->ssl_certificate_file = qd_entity_opt_string(entity, "certFile", 0); CHECK(); ssl_profile->ssl_private_key_file = qd_entity_opt_string(entity, "keyFile", 0); CHECK(); ssl_profile->ssl_password = qd_entity_opt_string(entity, "password", 0); CHECK(); if (!ssl_profile->ssl_password) { // SSL password not provided. Check if passwordFile property is specified. char *password_file = qd_entity_opt_string(entity, "passwordFile", 0); CHECK(); if (password_file) { FILE *file = fopen(password_file, "r"); if (file) { char buffer[200]; int c; int i=0; while (i < 200 - 1) { c = fgetc(file); if (c == EOF || c == '\n') break; buffer[i++] = c; } if (i != 0) { buffer[i] = '\0'; free(ssl_profile->ssl_password); ssl_profile->ssl_password = strdup(buffer); } fclose(file); } } free(password_file); } ssl_profile->ciphers = qd_entity_opt_string(entity, "ciphers", 0); CHECK(); ssl_profile->ssl_trusted_certificate_db = qd_entity_opt_string(entity, "certDb", 0); CHECK(); ssl_profile->ssl_trusted_certificates = qd_entity_opt_string(entity, "trustedCerts", 0); CHECK(); ssl_profile->ssl_uid_format = qd_entity_opt_string(entity, "uidFormat", 0); CHECK(); ssl_profile->ssl_display_name_file = qd_entity_opt_string(entity, "displayNameFile", 0); CHECK(); // // Process the password to handle any modifications or lookups needed // qd_config_ssl_profile_process_password(ssl_profile); CHECK(); qd_log(cm->log_source, QD_LOG_INFO, "Created SSL Profile with name %s ", ssl_profile->name); return ssl_profile; error: qd_log(cm->log_source, QD_LOG_ERROR, "Unable to create ssl profile: %s", qd_error_message()); config_ssl_profile_free(cm, ssl_profile); return 0; }
qd_error_t qd_py_to_composed(PyObject *value, qd_composed_field_t *field) { qd_python_check_lock(); qd_error_clear(); if (value == Py_None) { qd_compose_insert_null(field); } else if (PyBool_Check(value)) { qd_compose_insert_bool(field, PyInt_AS_LONG(value) ? 1 : 0); } else if (PyInt_Check(value)) { qd_compose_insert_long(field, (int64_t) PyInt_AS_LONG(value)); } else if (PyLong_Check(value)) { qd_compose_insert_long(field, (int64_t) PyLong_AsLongLong(value)); } else if (PyString_Check(value) || PyUnicode_Check(value)) { qd_compose_insert_string(field, PyString_AsString(value)); } else if (PyDict_Check(value)) { Py_ssize_t iter = 0; PyObject *key; PyObject *val; qd_compose_start_map(field); while (PyDict_Next(value, &iter, &key, &val)) { qd_py_to_composed(key, field); QD_ERROR_RET(); qd_py_to_composed(val, field); QD_ERROR_RET(); } QD_ERROR_PY_RET(); qd_compose_end_map(field); } else if (PyList_Check(value)) { Py_ssize_t count = PyList_Size(value); if (count == 0) qd_compose_empty_list(field); else { qd_compose_start_list(field); for (Py_ssize_t idx = 0; idx < count; idx++) { PyObject *item = PyList_GetItem(value, idx); QD_ERROR_PY_RET(); qd_py_to_composed(item, field); QD_ERROR_RET(); } qd_compose_end_list(field); } } else if (PyTuple_Check(value)) { Py_ssize_t count = PyTuple_Size(value); if (count == 0) qd_compose_empty_list(field); else { qd_compose_start_list(field); for (Py_ssize_t idx = 0; idx < count; idx++) { PyObject *item = PyTuple_GetItem(value, idx); QD_ERROR_PY_RET(); qd_py_to_composed(item, field); QD_ERROR_RET(); } qd_compose_end_list(field); } } else { PyObject *type=0, *typestr=0, *repr=0; if ((type = PyObject_Type(value)) && (typestr = PyObject_Str(type)) && (repr = PyObject_Repr(value))) qd_error(QD_ERROR_TYPE, "Can't compose object of type %s: %s", PyString_AsString(typestr), PyString_AsString(repr)); else qd_error(QD_ERROR_TYPE, "Can't compose python object of unknown type"); Py_XDECREF(type); Py_XDECREF(typestr); Py_XDECREF(repr); } return qd_error_code(); }
qd_error_t qd_router_python_setup(qd_router_t *router) { qd_error_clear(); log_source = qd_log_source("ROUTER"); qdr_core_route_table_handlers(router->router_core, router, qd_router_mobile_added, qd_router_mobile_removed, qd_router_link_lost); // // If we are not operating as an interior router, don't start the // router module. // if (router->router_mode != QD_ROUTER_MODE_INTERIOR) return QD_ERROR_NONE; PyObject *pDispatchModule = qd_python_module(); RouterAdapterType.tp_new = PyType_GenericNew; PyType_Ready(&RouterAdapterType); QD_ERROR_PY_RET(); PyTypeObject *raType = &RouterAdapterType; Py_INCREF(raType); PyModule_AddObject(pDispatchModule, "RouterAdapter", (PyObject*) &RouterAdapterType); // // Attempt to import the Python Router module // PyObject* pId; PyObject* pArea; PyObject* pMaxRouters; PyObject* pModule; PyObject* pClass; PyObject* pArgs; pModule = PyImport_ImportModule("qpid_dispatch_internal.router"); QD_ERROR_PY_RET(); pClass = PyObject_GetAttrString(pModule, "RouterEngine"); Py_DECREF(pModule); QD_ERROR_PY_RET(); PyObject *adapterType = PyObject_GetAttrString(pDispatchModule, "RouterAdapter"); QD_ERROR_PY_RET(); PyObject *adapterInstance = PyObject_CallObject(adapterType, 0); QD_ERROR_PY_RET(); ((RouterAdapter*) adapterInstance)->router = router; // // Constructor Arguments for RouterEngine // pArgs = PyTuple_New(4); // arg 0: adapter instance PyTuple_SetItem(pArgs, 0, adapterInstance); // arg 1: router_id pId = PyString_FromString(router->router_id); PyTuple_SetItem(pArgs, 1, pId); // arg 2: area_id pArea = PyString_FromString(router->router_area); PyTuple_SetItem(pArgs, 2, pArea); // arg 3: max_routers pMaxRouters = PyInt_FromLong((long) qd_bitmask_width()); PyTuple_SetItem(pArgs, 3, pMaxRouters); // // Instantiate the router // pyRouter = PyInstance_New(pClass, pArgs, 0); Py_DECREF(pArgs); Py_DECREF(adapterType); QD_ERROR_PY_RET(); pyTick = PyObject_GetAttrString(pyRouter, "handleTimerTick"); QD_ERROR_PY_RET(); pyAdded = PyObject_GetAttrString(pyRouter, "addressAdded"); QD_ERROR_PY_RET(); pyRemoved = PyObject_GetAttrString(pyRouter, "addressRemoved"); QD_ERROR_PY_RET(); pyLinkLost = PyObject_GetAttrString(pyRouter, "linkLost"); QD_ERROR_PY_RET(); return qd_error_code(); }
static qd_error_t load_server_config(qd_dispatch_t *qd, qd_server_config_t *config, qd_entity_t* entity) { qd_error_clear(); bool authenticatePeer = qd_entity_opt_bool(entity, "authenticatePeer", false); CHECK(); char *stripAnnotations = qd_entity_opt_string(entity, "stripAnnotations", 0); CHECK(); bool requireEncryption = qd_entity_opt_bool(entity, "requireEncryption", false); CHECK(); bool requireSsl = qd_entity_opt_bool(entity, "requireSsl", false); CHECK(); bool depRequirePeerAuth = qd_entity_opt_bool(entity, "requirePeerAuth", false); CHECK(); bool depAllowUnsecured = qd_entity_opt_bool(entity, "allowUnsecured", !requireSsl); CHECK(); memset(config, 0, sizeof(*config)); config->host = qd_entity_get_string(entity, "addr"); CHECK(); config->port = qd_entity_get_string(entity, "port"); CHECK(); config->name = qd_entity_opt_string(entity, "name", 0); CHECK(); config->role = qd_entity_get_string(entity, "role"); CHECK(); config->protocol_family = qd_entity_opt_string(entity, "protocolFamily", 0); CHECK(); config->max_frame_size = qd_entity_get_long(entity, "maxFrameSize"); CHECK(); config->idle_timeout_seconds = qd_entity_get_long(entity, "idleTimeoutSeconds"); CHECK(); config->sasl_username = qd_entity_opt_string(entity, "saslUsername", 0); CHECK(); config->sasl_password = qd_entity_opt_string(entity, "saslPassword", 0); CHECK(); config->sasl_mechanisms = qd_entity_opt_string(entity, "saslMechanisms", 0); CHECK(); config->ssl_enabled = has_attrs(entity, ssl_attributes, ssl_attributes_count); config->link_capacity = qd_entity_opt_long(entity, "linkCapacity", 0); CHECK(); // // Handle the defaults for link capacity. // if (config->link_capacity == 0) { if (strcmp("inter-router", config->role) == 0) config->link_capacity = 100000; // This is effectively infinite since session flow control will be more stringent. else config->link_capacity = 250; } // // For now we are hardwiring this attribute to true. If there's an outcry from the // user community, we can revisit this later. // config->allowInsecureAuthentication = true; load_strip_annotations(config, stripAnnotations); config->requireAuthentication = authenticatePeer || depRequirePeerAuth; config->requireEncryption = requireEncryption || !depAllowUnsecured; if (config->ssl_enabled) { config->ssl_required = requireSsl || !depAllowUnsecured; config->ssl_require_peer_authentication = config->sasl_mechanisms && strstr(config->sasl_mechanisms, "EXTERNAL") != 0; config->ssl_certificate_file = qd_entity_opt_string(entity, "certFile", 0); CHECK(); config->ssl_private_key_file = qd_entity_opt_string(entity, "keyFile", 0); CHECK(); config->ssl_password = qd_entity_opt_string(entity, "password", 0); CHECK(); config->ssl_trusted_certificate_db = qd_entity_opt_string(entity, "certDb", 0); CHECK(); config->ssl_trusted_certificates = qd_entity_opt_string(entity, "trustedCerts", 0); CHECK(); config->ssl_uid_format = qd_entity_opt_string(entity, "uidFormat", 0); CHECK(); config->ssl_display_name_file = qd_entity_opt_string(entity, "displayNameFile", 0); CHECK(); } free(stripAnnotations); return QD_ERROR_NONE; error: qd_server_config_free(config); return qd_error_code(); }
static qd_error_t load_server_config(qd_dispatch_t *qd, qd_server_config_t *config, qd_entity_t* entity, qd_config_ssl_profile_t **ssl_profile) { qd_error_clear(); bool authenticatePeer = qd_entity_opt_bool(entity, "authenticatePeer", false); CHECK(); bool verifyHostName = qd_entity_opt_bool(entity, "verifyHostName", true); CHECK(); char *stripAnnotations = qd_entity_opt_string(entity, "stripAnnotations", 0); CHECK(); bool requireEncryption = qd_entity_opt_bool(entity, "requireEncryption", false); CHECK(); bool requireSsl = qd_entity_opt_bool(entity, "requireSsl", false); CHECK(); bool depRequirePeerAuth = qd_entity_opt_bool(entity, "requirePeerAuth", false); CHECK(); bool depAllowUnsecured = qd_entity_opt_bool(entity, "allowUnsecured", !requireSsl); CHECK(); memset(config, 0, sizeof(*config)); config->port = qd_entity_get_string(entity, "port"); CHECK(); config->name = qd_entity_opt_string(entity, "name", 0); CHECK(); config->role = qd_entity_get_string(entity, "role"); CHECK(); config->inter_router_cost = qd_entity_opt_long(entity, "cost", 1); CHECK(); config->protocol_family = qd_entity_opt_string(entity, "protocolFamily", 0); CHECK(); config->max_frame_size = qd_entity_get_long(entity, "maxFrameSize"); CHECK(); config->max_sessions = qd_entity_get_long(entity, "maxSessions"); CHECK(); uint64_t ssn_frames = qd_entity_get_long(entity, "maxSessionFrames"); CHECK(); config->idle_timeout_seconds = qd_entity_get_long(entity, "idleTimeoutSeconds"); CHECK(); config->sasl_username = qd_entity_opt_string(entity, "saslUsername", 0); CHECK(); config->sasl_password = qd_entity_opt_string(entity, "saslPassword", 0); CHECK(); config->sasl_mechanisms = qd_entity_opt_string(entity, "saslMechanisms", 0); CHECK(); config->ssl_profile = qd_entity_opt_string(entity, "sslProfile", 0); CHECK(); config->link_capacity = qd_entity_opt_long(entity, "linkCapacity", 0); CHECK(); set_config_host(config, entity); // // Handle the defaults for various settings // if (config->link_capacity == 0) config->link_capacity = 250; if (config->max_sessions == 0 || config->max_sessions > 32768) // Proton disallows > 32768 config->max_sessions = 32768; if (config->max_frame_size < QD_AMQP_MIN_MAX_FRAME_SIZE) // Silently promote the minimum max-frame-size // Proton will do this but the number is needed for the // incoming capacity calculation. config->max_frame_size = QD_AMQP_MIN_MAX_FRAME_SIZE; // // Given session frame count and max frame size compute session incoming_capacity // Limit total capacity to 2^31-1. // uint64_t mfs = (uint64_t)config->max_frame_size; uint64_t trial_ic = ssn_frames * mfs; uint64_t limit = (1ll << 31) - 1; if (trial_ic < limit) { // Silently promote incoming capacity of zero to one config->incoming_capacity = (trial_ic < QD_AMQP_MIN_MAX_FRAME_SIZE ? QD_AMQP_MIN_MAX_FRAME_SIZE : trial_ic); } else { config->incoming_capacity = limit; uint64_t computed_ssn_frames = limit / mfs; qd_log(qd->connection_manager->log_source, QD_LOG_WARNING, "Server configuation for I/O adapter entity name:'%s', host:'%s', port:'%s', " "requested maxSessionFrames truncated from %llu to %llu", config->name, config->host, config->port, ssn_frames, computed_ssn_frames); } // // For now we are hardwiring this attribute to true. If there's an outcry from the // user community, we can revisit this later. // config->allowInsecureAuthentication = true; config->verify_host_name = verifyHostName; load_strip_annotations(config, stripAnnotations); config->requireAuthentication = authenticatePeer || depRequirePeerAuth; config->requireEncryption = requireEncryption || !depAllowUnsecured; if (config->ssl_profile) { config->ssl_required = requireSsl || !depAllowUnsecured; config->ssl_require_peer_authentication = config->sasl_mechanisms && strstr(config->sasl_mechanisms, "EXTERNAL") != 0; *ssl_profile = qd_find_ssl_profile(qd->connection_manager, config->ssl_profile); if (*ssl_profile) { config->ssl_certificate_file = (*ssl_profile)->ssl_certificate_file; config->ssl_private_key_file = (*ssl_profile)->ssl_private_key_file; config->ssl_password = (*ssl_profile)->ssl_password; config->ssl_trusted_certificate_db = (*ssl_profile)->ssl_trusted_certificate_db; config->ssl_trusted_certificates = (*ssl_profile)->ssl_trusted_certificates; config->ssl_uid_format = (*ssl_profile)->ssl_uid_format; config->ssl_display_name_file = (*ssl_profile)->ssl_display_name_file; } sys_atomic_inc(&(*ssl_profile)->ref_count); } free(stripAnnotations); return QD_ERROR_NONE; error: qd_server_config_free(config); return qd_error_code(); }