static int push_code_block(lang_c_ctx_t *ctx, parser_t *p, const char *buf, size_t sz) { code_block_t *node; dbg_return_if (p == NULL, ~0); dbg_return_if (ctx == NULL, ~0); node = (code_block_t*)u_zalloc(sizeof(code_block_t)); dbg_err_if(node == NULL); node->sz = sz; node->buf = (char*)u_malloc(sz); dbg_err_if(node->buf == NULL); node->code_line = p->code_line; node->file_in = ctx->ti->file_in; memcpy(node->buf, buf, sz); TAILQ_INSERT_TAIL(&ctx->code_blocks, node, np); return 0; err: if(node) free_code_block(node); return ~0; }
/** * \brief Fill a buffer object with the content of a file * * Open \p filename and copy its whole content into the given buffer \p ubuf * * \param ubuf an already allocated ::u_buf_t object * \param filename path of the source file * * \retval 0 on success * \retval ~0 on failure */ int u_buf_load (u_buf_t *ubuf, const char *filename) { struct stat st; FILE *fp = NULL; dbg_return_if (ubuf == NULL, ~0); dbg_return_if (filename == NULL, ~0); dbg_err_sif (stat(filename, &st) == -1); /* clear the current data */ dbg_err_if (u_buf_clear(ubuf)); /* be sure to have a big enough buffer */ dbg_err_if (u_buf_reserve(ubuf, st.st_size)); dbg_err_sifm ((fp = fopen(filename, "r")) == NULL, "%s", filename); /* fill the buffer with the whole file content */ dbg_err_if (fread(ubuf->data, st.st_size, 1, fp) != 1); ubuf->len = st.st_size; (void) fclose(fp); return 0; err: U_FCLOSE(fp); return ~0; }
/** * \brief tokenize the supplied \p wlist string * * Tokenize the \p delim separated string \p wlist and place its * pieces (at most \p tokv_sz - 1) into \p tokv. * * \param wlist list of strings possibily separated by chars in \p delim * \param delim set of token separators * \param tokv pre-allocated string array * \param tokv_sz number of cells in \p tokv array * */ int u_tokenize (char *wlist, const char *delim, char **tokv, size_t tokv_sz) { char **ap; dbg_return_if (wlist == NULL, ~0); dbg_return_if (delim == NULL, ~0); dbg_return_if (tokv == NULL, ~0); dbg_return_if (tokv_sz == 0, ~0); ap = tokv; for ( ; (*ap = strsep(&wlist, delim)) != NULL; ) { /* skip empty field */ if (**ap == '\0') continue; /* check bounds */ if (++ap >= &tokv[tokv_sz - 1]) break; } /* put an explicit stopper to tokv */ *ap = NULL; return 0; }
/** * \brief Save buffer to file * * Save the ::u_buf_t object \p ubuf to \p filename * * \param ubuf an already allocated ::u_buf_t object * \param filename path of the destination file * * \retval 0 on success * \retval ~0 on failure */ int u_buf_save (u_buf_t *ubuf, const char *filename) { dbg_return_if (ubuf == NULL, ~0); dbg_return_if (filename == NULL, ~0); return u_data_dump(u_buf_ptr(ubuf), u_buf_len(ubuf), filename); }
/** * \brief Log a \c KLOG message * * \param kl The klog context in use * \param level log severity, from KLOG_DEBUG to KLOG_EMERG * \param fmt log format string. Note that the conversion specification * depends on the underying log type: \c KLOG_TYPE_MEM and * \c KLOG_TYPE_FILE have printf(3)-like behaviour, while * \c KLOG_TYPE_SYSLOG follows syslog(3) format rules. * \param ... parameters to \p fmt * * \return * - \c 0 success * - \c ~0 on failure */ int klog (klog_t *kl, int level, const char *fmt, ...) { va_list ap; int rv = 0; dbg_return_if (kl == NULL, ~0); dbg_return_if (fmt == NULL, ~0); dbg_return_if (!IS_KLOG_TYPE(kl->type), ~0); va_start(ap, fmt); /* get rid of spurious stuff */ dbg_goto_if (level < KLOG_DEBUG || level >= KLOG_LEVEL_UNKNOWN, end); /* early filtering of msgs with level lower than threshold */ if (level < kl->threshold) goto end; /* if the log function is set call it with the supplied args */ if (kl->cb_log) rv = kl->cb_log(kl, level, fmt, ap); end: va_end(ap); return rv; }
static ssize_t gzip_transform(codec_t *codec, char *dst, size_t *dcount, const char *src, size_t src_sz) { codec_gzip_t *iz; size_t consumed; dbg_return_if (codec == NULL, -1); dbg_return_if (src == NULL, -1); dbg_return_if (dst == NULL, -1); dbg_return_if (dcount == NULL || *dcount == 0, -1); dbg_return_if (src_sz == 0, -1); iz = (codec_gzip_t*)codec; iz->zstr.next_out = dst; iz->zstr.avail_out = *dcount; iz->zstr.next_in = (char*)src; iz->zstr.avail_in = src_sz; iz->err = iz->op(&iz->zstr, Z_NO_FLUSH); dbg_err_if(iz->err != Z_OK && iz->err != Z_STREAM_END); consumed = src_sz - iz->zstr.avail_in; /* consumed */ *dcount = *dcount - iz->zstr.avail_out; /* written */ return consumed; /* # of consumed input bytes */ err: u_dbg("%s", zError(iz->err)); return -1; }
/** * \brief Parse an URI string and create the corresponding ::u_uri_t object * * Parse the NUL-terminated string \p uri and create an ::u_uri_t object at * \p *pu * * \param uri the NUL-terminated string that must be parsed * \param opts bitmask of or'ed ::u_uri_opts_t values * \param pu the newly created ::u_uri_t object containing the b * * \retval 0 on success * \retval ~0 on error */ int u_uri_crumble (const char *uri, u_uri_opts_t opts, u_uri_t **pu) { u_uri_t *u = NULL; int rc = 0; char es[1024]; regex_t re; regmatch_t pmatch[10]; dbg_return_if (uri == NULL, ~0); dbg_return_if (pu == NULL, ~0); dbg_err_if ((rc = regcomp(&re, uri_pat, REG_EXTENDED))); dbg_err_if ((rc = regexec(&re, uri, 10, pmatch, 0))); dbg_err_if (u_uri_new(opts, &u)); dbg_err_if (u_uri_fill(u, uri, pmatch)); regfree(&re); *pu = u; return 0; err: if (rc) { regerror(rc, &re, es, sizeof es); u_dbg("%s: %s", uri, es); } regfree(&re); if (u) u_uri_free(u); return ~0; }
/* map threshold directive to the internal representation */ static int klog_logopt (const char *options) { char *o2 = NULL; /* 'options' dupped for safe u_tokenize() */ int i, logopt = 0; enum { NOPTS = 4 }; char *optv[NOPTS + 1]; dbg_return_if (options == NULL, 0); dbg_return_if ((o2 = u_strdup(options)) == NULL, 0); dbg_err_if (u_tokenize(o2, " \t", optv, NOPTS + 1)); for (i = 0; optv[i] != NULL; i++) { if (!strcasecmp(optv[i], "LOG_CONS")) logopt |= LOG_CONS; else if (!strcasecmp(optv[i], "LOG_NDELAY")) logopt |= LOG_NDELAY; #ifdef HAVE_LOG_PERROR else if (!strcasecmp(optv[i], "LOG_PERROR")) logopt |= LOG_PERROR; #endif /* HAVE_LOG_PERROR */ else if (!strcasecmp(optv[i], "LOG_PID")) logopt |= LOG_PID; else warn("bad log option: \'%s\'", optv[i]); } U_FREE(o2); return logopt; err: U_FREE(o2); return 0; }
/** * \brief Create a new array object * * \param t the type of the elements in this array, i.e. one of * the standard C types (which have 1:1 mapping with * \c U_ARRAY_TYPE_*'s) or a pointer type (select * \c U_ARRAY_TYPE_PTR in this case) * \param nslots the initial number of slots to be created (set it to \c 0 * if you want the default) * \param pda the newly created array object as a result argument * * \retval 0 on success * \retval -1 on error */ int u_array_create (u_array_type_t t, size_t nslots, u_array_t **pda) { u_array_t *da = NULL; size_t max_nslots; dbg_return_if (pda == NULL, -1); dbg_return_if (!U_ARRAY_TYPE_IS_VALID(t), -1); da = u_zalloc(sizeof(u_array_t)); warn_err_sif (da == NULL); da->type = t; if (nslots == 0) da->nslots = U_ARRAY_NSLOTS_DFL; else if (nslots > (max_nslots = MAX_NSLOTS(da))) da->nslots = max_nslots; else da->nslots = nslots; da->base = u_zalloc(da->nslots * sizeof_type[da->type]); warn_err_sif (da->base == NULL); *pda = da; return 0; err: u_array_free(da); return -1; }
int normalize_origin(const char *o, char co[U_URI_STRMAX]) { u_uri_t *u = NULL; const char *scheme, *port; dbg_return_if(o == NULL || o[0] == '\0', -1); dbg_return_if(co == NULL, -1); dbg_err_ifm(u_uri_crumble(o, 0, &u), "%s parse error", o); /* Check that scheme is 'coap' or 'coaps'. */ dbg_err_ifm((scheme = u_uri_get_scheme(u)) == NULL || (strcasecmp(scheme, "coap") && strcasecmp(scheme, "coaps")), "bad %s scheme", scheme); /* Set default port if empty. */ if ((port = u_uri_get_port(u)) == NULL || *port == '\0') (void) u_uri_set_port(u, EC_COAP_DEFAULT_SPORT); dbg_err_ifm(u_uri_knead(u, co), "error normalizing origin (%s)", o); u_uri_free(u), u = NULL; return 0; err: if (u) u_uri_free(u); return -1; }
int vhost_load_contents(u_config_t *vhost, const char *origin) { size_t i; char wkc[1024] = { '\0' }; u_config_t *res, *contents; dbg_return_if(vhost == NULL, -1); dbg_return_if(origin == NULL, -1); /* Pick up the "contents" section. */ dbg_err_ifm(u_config_get_subkey(vhost, "contents", &contents), "no contents in virtual host !"); /* Load hosted resources. */ for (i = 0; (res = u_config_get_child_n(contents, "resource", i)) != NULL; ++i) { dbg_err_ifm(vhost_load_resource(res, origin), "error loading resource"); } dbg_err_ifm(i == 0, "no resources in virtual host"); /* Add the default /.well-known/core interface. */ dbg_err_if(u_snprintf(wkc, sizeof wkc, "%s/.well-known/core", origin)); CHAT("adding resource %s (AUTO)", wkc); dbg_err_ifm(ec_register_cb(g_ctx.coap, wkc, serve, NULL), "registering callback for %s failed", wkc); return 0; err: return -1; }
int vhost_load_allowed_methods(const char *m, ec_method_mask_t *pmm) { size_t nelems, i; char **tv = NULL; dbg_return_if(m == NULL, -1); dbg_return_if(pmm == NULL, -1); *pmm = EC_METHOD_MASK_UNSET; dbg_err_if(u_strtok(m, " \t", &tv, &nelems)); for (i = 0; i < nelems; ++i) { if (!strcasecmp(tv[i], "GET")) *pmm |= EC_GET_MASK; else if (!strcasecmp(tv[i], "POST")) *pmm |= EC_POST_MASK; else if (!strcasecmp(tv[i], "PUT")) *pmm |= EC_PUT_MASK; else if (!strcasecmp(tv[i], "DELETE")) *pmm |= EC_DELETE_MASK; else dbg_err("unknown method %s", tv[i]); } u_strtok_cleanup(tv, nelems); return 0; err: if (tv) u_strtok_cleanup(tv, nelems); return -1; }
int parse_addr(const char *ap, char *a, size_t a_sz, uint16_t *p) { int tmp; char *ptr; size_t alen; dbg_return_if(ap == NULL, -1); dbg_return_if(a == NULL, -1); dbg_return_if(a_sz == 0, -1); dbg_return_if(p == NULL, -1); /* Extract port, if specified. */ if ((ptr = strchr(ap, '+')) != NULL && ptr[1] != '\0') { dbg_err_ifm(u_atoi(++ptr, &tmp), "could not parse port %s", ptr); *p = (uint16_t) tmp; } else { ptr = (char *)(ap + strlen(ap) + 1); *p = EC_COAP_DEFAULT_PORT; } alen = (size_t)(ptr - ap - 1); dbg_err_ifm(alen >= a_sz, "not enough bytes (%zu vs %zu) to copy %s", alen, a_sz, ap); (void) strncpy(a, ap, alen); a[alen] = '\0'; return 0; err: return -1; }
/** * \brief Convert an asctime(3) string to \c time_t * * Convert the asctime(3) string \p str to its \c time_t representation \p tp. * * \param str the string to be converted * \param tp the \c time_t conversion of \p str as a value-result * argument * \return * - \c 0 successful * - \c ~0 failure */ int u_asctime_to_tt(const char *str, time_t *tp) { enum { BUFSZ = 64 }; char wday[BUFSZ], mon[BUFSZ]; unsigned int day, year, hour, min, sec; struct tm tm; int i; dbg_return_if (str == NULL, ~0); dbg_return_if (tp == NULL, ~0); dbg_return_if (strlen(str) >= BUFSZ, ~0); dbg_err_if((i = sscanf(str, "%s %s %u %u:%u:%u %u", wday, mon, &day, &hour, &min, &sec, &year)) != 7); memset(&tm, 0, sizeof(struct tm)); /* time */ tm.tm_sec = sec; tm.tm_min = min; tm.tm_hour = hour; /* date */ tm.tm_mday = day; tm.tm_mon = month_idx(mon); tm.tm_year = year - 1900; dbg_err_if(tm.tm_mon < 0); *tp = timegm(&tm); return 0; err: return ~0; }
/** * \brief Append a NUL-terminated string to a string object * * Append the NUL-terminated string \p buf to the ::u_string_t object \p s * * \param s an ::u_string_t object * \param buf NUL-terminated string that will be appended to \p s * \param len length of \p buf * * \retval 0 on success * \retval ~0 on failure */ int u_string_append (u_string_t *s, const char *buf, size_t len) { size_t nsz, min; dbg_return_if (s == NULL, ~0); dbg_return_if (buf == NULL, ~0); nop_return_if (len == 0, 0); /* nothing to do */ /* if there's not enough space on s->data alloc a bigger buffer */ if (s->data_len + len + 1 > s->data_sz) { min = s->data_len + len + 1; /* min required buffer length */ nsz = s->data_sz; while (nsz <= min) nsz += (BLOCK_SIZE << s->shift_cnt++); dbg_err_if (u_string_reserve(s, nsz)); } /* append this chunk to the data buffer */ strncpy(s->data + s->data_len, buf, len); s->data_len += len; s->data[s->data_len] = '\0'; return 0; err: return ~0; }
int var_create(const char* name, const char *value, var_t**pv) { dbg_return_if (name == NULL, ~0); dbg_return_if (value == NULL, ~0); return var_bin_create(name, (const unsigned char *) value, 1 + strlen(value), pv); }
static int klog_args_new (klog_args_t **pka) { dbg_return_if (pka == NULL, ~0); *pka = u_zalloc(sizeof(klog_args_t)); dbg_return_if (*pka == NULL, ~0); return 0; }
/** * \brief create a \c klog_args_t object with configuration parameters read * from a log subsection of a kloned configuration file * * \param ls a log configuration record * \param pka the corresponding \c klog_args_t object as a value-result * argument * \return * - \c 0 success * - \c ~0 on failure (\p pka MUST not be referenced) */ int klog_args (u_config_t *ls, klog_args_t **pka) { const char *cs; klog_args_t *ka = NULL; dbg_return_if (ls == NULL, ~0); dbg_return_if (pka == NULL, ~0); /* here defaults are set */ dbg_err_if (klog_args_new(&ka)); /* read in config values */ ka->type = klog_type(u_config_get_subkey_value(ls, "type")); if ((cs = u_config_get_subkey_value(ls, "ident")) != NULL) ka->ident = u_strdup(cs); ka->threshold = klog_threshold(u_config_get_subkey_value(ls, "threshold")); if ((cs = u_config_get_subkey_value(ls, "memory.limit")) != NULL) { dbg_err_ifm (u_atoi(cs, &ka->mlimit), "'memory.limit' bad value: %s", cs); } if ((cs = u_config_get_subkey_value(ls, "file.basename")) != NULL) ka->fbasename = u_strdup(cs); if ((cs = u_config_get_subkey_value(ls, "file.limit")) != NULL) { dbg_err_ifm (u_atoi(cs, &ka->flimit), "'file.limit' bad value: %s", cs); } if ((cs = u_config_get_subkey_value(ls, "file.splits")) != NULL) { dbg_err_ifm (u_atoi(cs, &ka->fsplits), "'file.splits' bad value: %s", cs); } #ifdef HAVE_SYSLOG ka->sfacility = klog_facility(ka, u_config_get_subkey_value(ls, "syslog.facility")); ka->soptions = klog_logopt(u_config_get_subkey_value(ls, "syslog.options")); #endif dbg_return_if (klog_args_check(ka), ~0); *pka = ka; return 0; err: if (ka) klog_args_free(ka); return ~0; }
/** * \brief Copy the value of a string to another * * Copy \p src string to \p dst string. Both \p src and \p dst must be * already TODO... * * \param dst destination ::u_string_t object * \param src source ::u_string_t object * * \retval 0 on success * \retval ~0 on failure */ inline int u_string_copy (u_string_t *dst, u_string_t *src) { dbg_return_if (dst == NULL, ~0); dbg_return_if (src == NULL, ~0); (void) u_string_clear(dst); return u_string_append(dst, src->data, src->data_len); }
/** * \ingroup vars * \brief Set the value of a variable * * Set the value of variable \p v to \p value * * \param v variable object * \param value variable value (null-terminated) * * \return \c 0 if successful, non-zero on error */ int var_set_value(var_t *v, const char *value) { dbg_return_if (v == NULL, ~0); dbg_return_if (value == NULL, ~0); /* copy the string and the trailing '\0' */ return var_set_bin_value(v, (const unsigned char *) value, 1 + strlen(value)); }
/** * \brief Return the nth memory-log message * * \param kl A \c KLOG_TYPE_MEM context * \param nth a log message index: elements are retrieved in reverse order * with respect to insertion * \param ln where the log string shall be stored: it must be a preallocated * buffer, at least \c KLOG_MSG_SZ \c + \c 1 bytes long * \return * - \c 0 success * - \c ~0 on failure */ int klog_getln (klog_t *kl, size_t nth, char ln[]) { dbg_return_if (kl == NULL, ~0); dbg_return_if (!IS_KLOG_TYPE(kl->type), ~0); if (kl->cb_getln) return kl->cb_getln(kl, nth, ln); return 0; }
/** * \brief Remove all memory-log messages from the supplied \c klog_t context * * \param kl A \c KLOG_TYPE_MEM context * * \return * - \c 0 success * - \c ~0 on failure */ int klog_clear (klog_t *kl) { dbg_return_if (kl == NULL, ~0); dbg_return_if (!IS_KLOG_TYPE(kl->type), ~0); if (kl->cb_clear) return kl->cb_clear(kl); return ~0; }
/** * \brief Count the number of lines in the supplied memory-log context \p kl * * \param kl A \c KLOG_TYPE_MEM context * * \return nothing */ ssize_t klog_countln (klog_t *kl) { dbg_return_if (kl == NULL, -1); dbg_return_if (!IS_KLOG_TYPE(kl->type), ~0); if (kl->cb_countln) return kl->cb_countln(kl); return -1; /* XXX should be 0 ? */ }
int ec_rep_del(ec_res_t *res, ec_rep_t *rep) { dbg_return_if (res == NULL, -1); dbg_return_if (rep == NULL, -1); TAILQ_REMOVE(&res->reps, rep, next); ec_rep_free(rep); return 0; }
static int server_be_listen(backend_t *be) { dbg_return_if (be == NULL, ~0); dbg_return_if (be->na == NULL, ~0); /* Return a socket descriptor bound to the configured endpoint. */ warn_return_if ((be->ld = u_net_sd_by_addr(be->na)) == -1, ~0); return 0; }
/** * \brief flush all buffered data to the \c klog_t (file) device * * \param kl a klog device * * \return * - \c 0 success * - \c ~0 on failure */ int klog_flush (klog_t *kl) { dbg_return_if (kl == NULL, ~0); dbg_return_if (!IS_KLOG_TYPE(kl->type), ~0); /* call private flush function */ if (kl->cb_flush) return kl->cb_flush(kl); return 0; }
/* Duplicate the bits needed to identify the observer. */ int ec_conn_copy(const ec_conn_t *src, ec_conn_t *dst) { dbg_return_if (src == NULL, -1); dbg_return_if (dst == NULL, -1); dst->socket = src->socket; memcpy(&dst->peer, &src->peer, sizeof dst->peer); /* TODO copy in security context. */ return 0; }
/** * \brief Set the value of a buffer * * Explicitly set the value of \a ubuf to \a data. If needed the buffer * object will call ::u_buf_append to enlarge the storage needed to copy-in * the \a data value. * * \param ubuf a previously allocated ::u_buf_t object * \param data a reference to the memory block that will be copied into * the buffer * \param size size of \a data in bytes * * \retval 0 on success * \retval ~0 on error */ int u_buf_set (u_buf_t *ubuf, const void *data, size_t size) { dbg_return_if (ubuf == NULL, ~0); dbg_return_if (data == NULL, ~0); dbg_return_if (size == 0, ~0); dbg_err_if (u_buf_clear(ubuf)); dbg_err_if (u_buf_append(ubuf, data, size)); return 0; err: return ~0; }
int ec_conn_save_peer(ec_conn_t *conn, const struct sockaddr_storage *peer) { uint8_t peer_len; dbg_return_if (conn == NULL, -1); dbg_return_if (peer == NULL, -1); dbg_return_if (ec_net_socklen(peer, &peer_len), -1); memcpy(&conn->peer, peer, peer_len); return 0; }
/** * \brief Convert an HTTP time string to \c time_t * * Convert the HTTP time string \p str to its \c time_t representation \p tp. * * \param str the string to be converted * \param tp the \c time_t conversion of \p str as a value-result * argument * \return * - \c 0 successful * - \c ~0 failure */ int u_httpdate_to_tt(const char *str, time_t *tp) { dbg_return_if (str == NULL, ~0); dbg_return_if (tp == NULL, ~0); dbg_return_if (strlen(str) < 4, ~0); if(str[3] == ',') return u_rfc822_to_tt(str, tp); else if(str[3] == ' ') return u_asctime_to_tt(str, tp); return u_rfc850_to_tt(str, tp); }