1 /* 2 * Copyright (C) 2011-2014 Felix Fietkau <nbd@openwrt.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License version 2.1 6 * as published by the Free Software Foundation 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14 #include <sys/types.h> 15 #include <sys/socket.h> 16 #include <unistd.h> 17 18 #include <libubox/blob.h> 19 #include <libubox/blobmsg.h> 20 21 #include "libubus.h" 22 #include "libubus-internal.h" 23 #include "ubusmsg.h" 24 25 const char *__ubus_strerror[__UBUS_STATUS_LAST] = { 26 [UBUS_STATUS_OK] = "Success", 27 [UBUS_STATUS_INVALID_COMMAND] = "Invalid command", 28 [UBUS_STATUS_INVALID_ARGUMENT] = "Invalid argument", 29 [UBUS_STATUS_METHOD_NOT_FOUND] = "Method not found", 30 [UBUS_STATUS_NOT_FOUND] = "Not found", 31 [UBUS_STATUS_NO_DATA] = "No response", 32 [UBUS_STATUS_PERMISSION_DENIED] = "Permission denied", 33 [UBUS_STATUS_TIMEOUT] = "Request timed out", 34 [UBUS_STATUS_NOT_SUPPORTED] = "Operation not supported", 35 [UBUS_STATUS_UNKNOWN_ERROR] = "Unknown error", 36 [UBUS_STATUS_CONNECTION_FAILED] = "Connection failed", 37 [UBUS_STATUS_NO_MEMORY] = "Out of memory", 38 [UBUS_STATUS_PARSE_ERROR] = "Parsing message data failed", 39 [UBUS_STATUS_SYSTEM_ERROR] = "System error", 40 }; 41 42 struct blob_buf b __hidden = {}; 43 44 struct ubus_pending_msg { 45 struct list_head list; 46 struct ubus_msghdr_buf hdr; 47 }; 48 49 static int ubus_cmp_id(const void *k1, const void *k2, void *ptr) 50 { 51 const uint32_t *id1 = k1, *id2 = k2; 52 53 if (*id1 < *id2) 54 return -1; 55 else 56 return *id1 > *id2; 57 } 58 59 const char *ubus_strerror(int error) 60 { 61 static char err[32]; 62 63 if (error < 0 || error >= __UBUS_STATUS_LAST) 64 goto out; 65 66 if (!__ubus_strerror[error]) 67 goto out; 68 69 return __ubus_strerror[error]; 70 71 out: 72 sprintf(err, "Unknown error: %d", error); 73 return err; 74 } 75 76 static void 77 ubus_queue_msg(struct ubus_context *ctx, struct ubus_msghdr_buf *buf) 78 { 79 struct ubus_pending_msg *pending; 80 void *data; 81 82 pending = calloc_a(sizeof(*pending), &data, blob_raw_len(buf->data)); 83 84 pending->hdr.data = data; 85 memcpy(&pending->hdr.hdr, &buf->hdr, sizeof(buf->hdr)); 86 memcpy(data, buf->data, blob_raw_len(buf->data)); 87 list_add_tail(&pending->list, &ctx->pending); 88 if (ctx->sock.registered) 89 uloop_timeout_set(&ctx->pending_timer, 1); 90 } 91 92 void __hidden 93 ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr_buf *buf, int fd) 94 { 95 switch(buf->hdr.type) { 96 case UBUS_MSG_STATUS: 97 case UBUS_MSG_DATA: 98 ubus_process_req_msg(ctx, buf, fd); 99 break; 100 101 case UBUS_MSG_INVOKE: 102 case UBUS_MSG_UNSUBSCRIBE: 103 case UBUS_MSG_NOTIFY: 104 if (ctx->stack_depth) { 105 ubus_queue_msg(ctx, buf); 106 break; 107 } 108 109 ctx->stack_depth++; 110 ubus_process_obj_msg(ctx, buf, fd); 111 ctx->stack_depth--; 112 break; 113 case UBUS_MSG_MONITOR: 114 if (ctx->monitor_cb) 115 ctx->monitor_cb(ctx, buf->hdr.seq, buf->data); 116 break; 117 } 118 } 119 120 static void ubus_process_pending_msg(struct uloop_timeout *timeout) 121 { 122 struct ubus_context *ctx = container_of(timeout, struct ubus_context, pending_timer); 123 struct ubus_pending_msg *pending; 124 125 while (!list_empty(&ctx->pending)) { 126 if (ctx->stack_depth) 127 break; 128 129 pending = list_first_entry(&ctx->pending, struct ubus_pending_msg, list); 130 list_del(&pending->list); 131 ubus_process_msg(ctx, &pending->hdr, -1); 132 free(pending); 133 } 134 } 135 136 struct ubus_lookup_request { 137 struct ubus_request req; 138 ubus_lookup_handler_t cb; 139 }; 140 141 static void ubus_lookup_cb(struct ubus_request *ureq, int type, struct blob_attr *msg) 142 { 143 struct ubus_lookup_request *req; 144 struct ubus_object_data obj = {}; 145 struct blob_attr **attr; 146 147 req = container_of(ureq, struct ubus_lookup_request, req); 148 attr = ubus_parse_msg(msg, blob_raw_len(msg)); 149 150 if (!attr[UBUS_ATTR_OBJID] || !attr[UBUS_ATTR_OBJPATH] || 151 !attr[UBUS_ATTR_OBJTYPE]) 152 return; 153 154 obj.id = blob_get_u32(attr[UBUS_ATTR_OBJID]); 155 obj.path = blob_data(attr[UBUS_ATTR_OBJPATH]); 156 obj.type_id = blob_get_u32(attr[UBUS_ATTR_OBJTYPE]); 157 obj.signature = attr[UBUS_ATTR_SIGNATURE]; 158 req->cb(ureq->ctx, &obj, ureq->priv); 159 } 160 161 int ubus_lookup(struct ubus_context *ctx, const char *path, 162 ubus_lookup_handler_t cb, void *priv) 163 { 164 struct ubus_lookup_request lookup; 165 166 blob_buf_init(&b, 0); 167 if (path) 168 blob_put_string(&b, UBUS_ATTR_OBJPATH, path); 169 170 if (ubus_start_request(ctx, &lookup.req, b.head, UBUS_MSG_LOOKUP, 0) < 0) 171 return UBUS_STATUS_INVALID_ARGUMENT; 172 173 lookup.req.raw_data_cb = ubus_lookup_cb; 174 lookup.req.priv = priv; 175 lookup.cb = cb; 176 return ubus_complete_request(ctx, &lookup.req, 0); 177 } 178 179 static void ubus_lookup_id_cb(struct ubus_request *req, int type, struct blob_attr *msg) 180 { 181 struct blob_attr **attr; 182 uint32_t *id = req->priv; 183 184 attr = ubus_parse_msg(msg, blob_raw_len(msg)); 185 186 if (!attr[UBUS_ATTR_OBJID]) 187 return; 188 189 *id = blob_get_u32(attr[UBUS_ATTR_OBJID]); 190 } 191 192 int ubus_lookup_id(struct ubus_context *ctx, const char *path, uint32_t *id) 193 { 194 struct ubus_request req; 195 196 blob_buf_init(&b, 0); 197 if (path) 198 blob_put_string(&b, UBUS_ATTR_OBJPATH, path); 199 200 if (ubus_start_request(ctx, &req, b.head, UBUS_MSG_LOOKUP, 0) < 0) 201 return UBUS_STATUS_INVALID_ARGUMENT; 202 203 req.raw_data_cb = ubus_lookup_id_cb; 204 req.priv = id; 205 206 return ubus_complete_request(ctx, &req, 0); 207 } 208 209 static int ubus_event_cb(struct ubus_context *ctx, struct ubus_object *obj, 210 struct ubus_request_data *req, 211 const char *method, struct blob_attr *msg) 212 { 213 struct ubus_event_handler *ev; 214 215 ev = container_of(obj, struct ubus_event_handler, obj); 216 ev->cb(ctx, ev, method, msg); 217 return 0; 218 } 219 220 static const struct ubus_method event_method = { 221 .name = NULL, 222 .handler = ubus_event_cb, 223 }; 224 225 int ubus_register_event_handler(struct ubus_context *ctx, 226 struct ubus_event_handler *ev, 227 const char *pattern) 228 { 229 struct ubus_object *obj = &ev->obj; 230 struct blob_buf b2 = {}; 231 int ret; 232 233 if (!obj->id) { 234 obj->methods = &event_method; 235 obj->n_methods = 1; 236 237 if (!!obj->name ^ !!obj->type) 238 return UBUS_STATUS_INVALID_ARGUMENT; 239 240 ret = ubus_add_object(ctx, obj); 241 if (ret) 242 return ret; 243 } 244 245 /* use a second buffer, ubus_invoke() overwrites the primary one */ 246 blob_buf_init(&b2, 0); 247 blobmsg_add_u32(&b2, "object", obj->id); 248 if (pattern) 249 blobmsg_add_string(&b2, "pattern", pattern); 250 251 ret = ubus_invoke(ctx, UBUS_SYSTEM_OBJECT_EVENT, "register", b2.head, 252 NULL, NULL, 0); 253 blob_buf_free(&b2); 254 255 return ret; 256 } 257 258 int ubus_send_event(struct ubus_context *ctx, const char *id, 259 struct blob_attr *data) 260 { 261 struct ubus_request req; 262 void *s; 263 264 blob_buf_init(&b, 0); 265 blob_put_int32(&b, UBUS_ATTR_OBJID, UBUS_SYSTEM_OBJECT_EVENT); 266 blob_put_string(&b, UBUS_ATTR_METHOD, "send"); 267 s = blob_nest_start(&b, UBUS_ATTR_DATA); 268 blobmsg_add_string(&b, "id", id); 269 blobmsg_add_field(&b, BLOBMSG_TYPE_TABLE, "data", blob_data(data), blob_len(data)); 270 blob_nest_end(&b, s); 271 272 if (ubus_start_request(ctx, &req, b.head, UBUS_MSG_INVOKE, UBUS_SYSTEM_OBJECT_EVENT) < 0) 273 return UBUS_STATUS_INVALID_ARGUMENT; 274 275 return ubus_complete_request(ctx, &req, 0); 276 } 277 278 static void ubus_default_connection_lost(struct ubus_context *ctx) 279 { 280 if (ctx->sock.registered) 281 uloop_end(); 282 } 283 284 int ubus_connect_ctx(struct ubus_context *ctx, const char *path) 285 { 286 uloop_init(); 287 memset(ctx, 0, sizeof(*ctx)); 288 289 ctx->sock.fd = -1; 290 ctx->sock.cb = ubus_handle_data; 291 ctx->connection_lost = ubus_default_connection_lost; 292 ctx->pending_timer.cb = ubus_process_pending_msg; 293 294 ctx->msgbuf.data = calloc(1, UBUS_MSG_CHUNK_SIZE); 295 if (!ctx->msgbuf.data) 296 return -1; 297 ctx->msgbuf_data_len = UBUS_MSG_CHUNK_SIZE; 298 299 INIT_LIST_HEAD(&ctx->requests); 300 INIT_LIST_HEAD(&ctx->pending); 301 INIT_LIST_HEAD(&ctx->auto_subscribers); 302 avl_init(&ctx->objects, ubus_cmp_id, false, NULL); 303 if (ubus_reconnect(ctx, path)) { 304 free(ctx->msgbuf.data); 305 ctx->msgbuf.data = NULL; 306 return -1; 307 } 308 309 return 0; 310 } 311 312 static void ubus_auto_reconnect_cb(struct uloop_timeout *timeout) 313 { 314 struct ubus_auto_conn *conn = container_of(timeout, struct ubus_auto_conn, timer); 315 316 if (!ubus_reconnect(&conn->ctx, conn->path)) 317 ubus_add_uloop(&conn->ctx); 318 else 319 uloop_timeout_set(timeout, 1000); 320 } 321 322 static void ubus_auto_disconnect_cb(struct ubus_context *ctx) 323 { 324 struct ubus_auto_conn *conn = container_of(ctx, struct ubus_auto_conn, ctx); 325 326 conn->timer.cb = ubus_auto_reconnect_cb; 327 uloop_timeout_set(&conn->timer, 1000); 328 } 329 330 static void ubus_auto_connect_cb(struct uloop_timeout *timeout) 331 { 332 struct ubus_auto_conn *conn = container_of(timeout, struct ubus_auto_conn, timer); 333 334 if (ubus_connect_ctx(&conn->ctx, conn->path)) { 335 uloop_timeout_set(timeout, 1000); 336 fprintf(stderr, "failed to connect to ubus\n"); 337 return; 338 } 339 conn->ctx.connection_lost = ubus_auto_disconnect_cb; 340 if (conn->cb) 341 conn->cb(&conn->ctx); 342 ubus_add_uloop(&conn->ctx); 343 } 344 345 void ubus_auto_connect(struct ubus_auto_conn *conn) 346 { 347 conn->timer.cb = ubus_auto_connect_cb; 348 ubus_auto_connect_cb(&conn->timer); 349 } 350 351 struct ubus_context *ubus_connect(const char *path) 352 { 353 struct ubus_context *ctx; 354 355 ctx = calloc(1, sizeof(*ctx)); 356 if (!ctx) 357 return NULL; 358 359 if (ubus_connect_ctx(ctx, path)) { 360 free(ctx); 361 ctx = NULL; 362 } 363 364 return ctx; 365 } 366 367 void ubus_shutdown(struct ubus_context *ctx) 368 { 369 blob_buf_free(&b); 370 if (!ctx) 371 return; 372 uloop_fd_delete(&ctx->sock); 373 close(ctx->sock.fd); 374 uloop_timeout_cancel(&ctx->pending_timer); 375 free(ctx->msgbuf.data); 376 } 377 378 void ubus_free(struct ubus_context *ctx) 379 { 380 ubus_shutdown(ctx); 381 free(ctx); 382 } 383
This page was automatically generated by LXR 0.3.1. • OpenWrt