/** * add a data item to the end of the list **/ void pl_add_tail(pointer_list_t *pl, const void *data) { pointer_list_entry_t *e; e = (pointer_list_entry_t*) ll_add_tail(pl); e->data = data; }
int sll_add(struct sortedll_st* sll, void* val) { assert(sll); assert(sll->ll); int syserr = -1; struct lnkelm_st* le = sll->ll->head.next; struct lnkelm_st* add = NULL; for (; le->next; le=le->next) { int cmp = sll->cmp_val(le->val, val); if (cmp > 0) { add = ll_add_prev(le, val); if (! add) { goto EXIT_LABEL; } break; } else if (cmp == 0) { if (sll->opts & SLLOPT_DISALLOW_DUPVAL) { syserr = SLLERR_DISALLOW_DUPVAL; goto EXIT_LABEL; } } } if (! add) { add = ll_add_tail(sll->ll, val); if (! add) { goto EXIT_LABEL; } } syserr = 0; EXIT_LABEL: return syserr; }
/* start a monitored thread. If it dies, it will be restarted the thread identification information will be stored in the thread parameter */ int _xbee_threadStartMonitored(struct xbee *xbee, xsys_thread *thread, void*(*start_routine)(void*), void *arg, char *funcName) { struct threadInfo *tinfo; /* check parameters */ if (!xbee) { if (!xbee_default) return XBEE_ENOXBEE; xbee = xbee_default; } if (!xbee_validate(xbee)) return XBEE_EINVAL; if (!thread) return XBEE_EMISSINGPARAM; if (!start_routine) return XBEE_EMISSINGPARAM; if (!arg) return XBEE_EMISSINGPARAM; if (!funcName) return XBEE_EMISSINGPARAM; /* find out if we are already monitoring that function, and with the same argument */ for (tinfo = NULL; (tinfo = ll_get_next(&xbee->threadList, tinfo)) != NULL;) { /* is that handle already being used? */ if (tinfo->thread == thread) return XBEE_EINUSE; /* is that exact func/arg combo already being used? that would be a bit silly... */ if (tinfo->start_routine == start_routine && tinfo->arg == arg) { return XBEE_EEXISTS; } } /* create a new block */ if ((tinfo = calloc(1, sizeof(struct threadInfo))) == NULL) { return XBEE_ENOMEM; } /* setup all the details */ tinfo->funcName = funcName; tinfo->start_routine = start_routine; tinfo->arg = arg; tinfo->thread = thread; /* add it to the threadList */ if (ll_add_tail(&xbee->threadList, tinfo)) { return XBEE_ELINKEDLIST; } /* and prod the monitor thread (who will start the thread for us! */ xsys_sem_post(&xbee->semMonitor); return XBEE_ENONE; }
static int on_OK_read_chunk(const struct jbxm_initconf_st* iconf, struct jbxm_callback_if_st* cbif) { assert(iconf); assert(cbif); assert(cbif->type == JBXM_CBT_OK_RCHUNK); assert(cbif->io_area->avail > 0); struct UserData_st* ud = dbGET(cbif, "user-data"); assert(ud); if (ud->bodylen) { size_t remain_size = recordio_get_remain_size(cbif); if ((ud->body_chunks_sumlen + remain_size) >= ud->bodylen) { // 溜め込んだものと、レコード生成中のものをあわせて Content-Length 以上になったら入力終了 if (remain_size) { struct varmem_st* vm = new_varmem(remain_size); assert(vm); recordio_move_remain_data(cbif, vm->bytes); void* ok = ll_add_tail(ud->body_chunks, vm); assert(ok); ud->body_chunks_sumlen += remain_size; } //PRINT("body_chunks_sumlen=%d remain_size=%zu", ud->body_chunks_sumlen, remain_size); //ll_foreach(ud->body_chunks, print_body_chunk_, NULL); ud->response = http_CreateResponse(ud); cbif->flow->next_events = EPOLLOUT | EPOLLET; } } return 0; }
int hm_set(const struct hashmap_st* hm, const char* key, void* val, void** old_val) { int syserr = -1; assert(hm); assert(key); int idx = hm_str2code(key) % (int)hm->array_num; struct kv_st* kv = NULL; struct lnklst_st* ll = hm->array[idx]; if (! ll) { if (! val) { if (old_val) { *old_val = NULL; } syserr = 0; goto EXIT_LABEL; } ll = ll_init(free_kv_); if (! ll) { goto EXIT_LABEL; } hm->array[idx] = ll; } struct lnkelm_st* le = ll_search(ll, NULL, cmp_by_key_, key); if (le) { struct kv_st* tmp_kv = le->val; if (old_val) { *old_val = tmp_kv->val; } if (val) { tmp_kv->val = val; } else { ll_del(ll, le); } } else { if (old_val) { *old_val = NULL; } if (! val) { syserr = 0; goto EXIT_LABEL; } kv = calloc(1, sizeof(struct kv_st)); if (! kv) { goto EXIT_LABEL; } kv->key = strdup(key); if (! kv->key) { goto EXIT_LABEL; } kv->val = val; void* ok = ll_add_tail(ll, kv); if (! ok) { goto EXIT_LABEL; } } syserr = 0; EXIT_LABEL: if (syserr) { if (kv) { free(kv->key); free(kv); } } return syserr; }
static struct lnklst_st* new_lstnmods_(struct sortedll_st* ports, struct lnklst_st* fkvs) { FUNC_ENTER struct lnklst_st* lstnmods = NULL; struct cbmod_st* defset = NULL; struct cbmod_st* cbmod = NULL; defset = new_default_cbmod(fkvs, "/listen-module-default"); if (! defset) { FIRE("new_default_cbmod_"); } defset->iconf->cbmt = JBXM_CBMT_LISTEN; //puts("# defset -->"); //print_cbmod_(defset, NULL); //puts("# defset --<"); lstnmods = ll_init(free_cbmod); if (! lstnmods) { FIRE("ll_init"); } char family[32] = ""; for (struct lnkelm_st* le=sll_first(ports); le->next; le=le->next) { // ポート番号を数値に変換 intptr_t n_port = (intptr_t)le->val; // デフォルト値をコピーする (family_, name, port 以外) cbmod = new_copy_cbmod_attr(defset); if (! cbmod) { FIRE("new_copy_cbmod"); } snprintf(family, sizeof family, "/listen-modules/%zd", n_port); // family_ をコピー cbmod->family_ = strdup(family); if (! cbmod->family_) { FIRE("strdup"); } // family_ の値を元に conf から値を設定する syserr = ll_foreach(fkvs, set_cbmod_by_family, cbmod); if (syserr) { FIRE("ll_foreach"); } if (! is_valid_cbmod(cbmod)) { FIRE("is_valid_cbmod port=%ld", n_port); } cbmod->iconf->port = (u_short)n_port; if (cbmod->enable) { print_cbmod(cbmod, NULL); void* ok = ll_add_tail(lstnmods, cbmod); if (! ok) { FIRE("ll_add"); } cbmod = NULL; } else { DBGLOG("port(%u) disable", cbmod->iconf->port); free_cbmod(cbmod); cbmod = NULL; } } FUNC_CHECKPOINT if (HAS_ERROR()) { free_cbmod(cbmod); cbmod = NULL; ll_free(lstnmods); lstnmods = NULL; } free_cbmod(defset); defset = NULL; FUNC_LEAVE return lstnmods; }
static int on_OK_read_chunk(const struct jbxm_initconf_st* iconf, struct jbxm_callback_if_st* cbif) { assert(iconf); assert(cbif); assert(cbif->type == JBXM_CBT_OK_RCHUNK); assert(cbif->io_area->avail > 0); int syserr = -1; bool success = false; struct varmem_st* vm = NULL; unsigned char* buff = NULL; struct type2cb_st t2cb = { 0 }; syserr = type2bcb_(iconf, JBXM_CBT_OK_RBINARY, &t2cb); assert(syserr == 0); if (! t2cb.func) { // on_OK_read_binary() が設定されていないので終了 success = true; goto EXIT_LABEL; } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wbad-function-cast" size_t reqsiz = (size_t)dbGET(cbif, ".libjbx-readreq-size"); #pragma GCC diagnostic pop assert(reqsiz); struct libjbxm_rdata_st* rd = dbGET(cbif, ".libjbxm-readdata"); assert(rd); // vm = calloc(1, sizeof(struct varmem_st)); if (! vm) { goto EXIT_LABEL; } vm->bytes = cbif->io_area->buff; cbif->io_area->buff = NULL; // move memory vm->bytes_len = (size_t)cbif->io_area->avail; // void* ok = ll_add_tail(rd->chunks, vm); if (! ok) { goto EXIT_LABEL; } vm = NULL; // move memory rd->chunks_sumlen += (size_t)cbif->io_area->avail; // assert(rd->chunks_sumlen <= reqsiz); if (rd->chunks_sumlen < reqsiz) { success = true; goto EXIT_LABEL; } // chunks を結合 assert(rd->chunks_sumlen == reqsiz); buff = malloc(reqsiz + 1); if (! buff) { goto EXIT_LABEL; } unsigned char* pos = buff; ll_foreach(rd->chunks, varmem_concat_, &pos); *(buff + reqsiz) = '\0'; // chunks をクリア ll_clear(rd->chunks); rd->chunks_sumlen = 0; // type, io_area の内容を変更する必要があるのでコピーして一部置き換え struct jbxm_io_area_st io_area = { .buff=buff, .bufsiz=reqsiz, .ok=true, .avail=(ssize_t)reqsiz, }; buff = NULL; // move memory struct jbxm_callback_if_st tmp_cbif = *cbif; tmp_cbif.type = t2cb.type; tmp_cbif.io_area = &io_area; syserr = t2cb.func(iconf, &tmp_cbif); free(io_area.buff); if (syserr) { goto EXIT_LABEL; } // 次回の on_pre_read_binary() で要求サイズを再設定させるためにクリア dbUNSET0(cbif, ".libjbx-readreq-size"); success = true; EXIT_LABEL: free(buff); if (! success) { free_varmem(vm); return -1; } return 0; } static int on_pre_write_chunk(const struct jbxm_initconf_st* iconf, struct jbxm_callback_if_st* cbif) { struct type2cb_st t2cb = { 0 }; int syserr = type2bcb_(iconf, JBXM_CBT_PRE_WBINARY, &t2cb); assert(syserr == 0); return libjbxm_on_pre_write_chunk(iconf, cbif, &t2cb); } static int on_post_write_chunk(const struct jbxm_initconf_st* iconf, struct jbxm_callback_if_st* cbif) { struct type2cb_st t2cb = { 0 }; int syserr = type2bcb_(iconf, JBXM_CBT_POST_WBINARY, &t2cb); assert(syserr == 0); return libjbxm_on_post_write_chunk(iconf, cbif, &t2cb); } struct libjbxm_io_st binaryio = { .callbacks = { // load, unload .on_load = call_original, .on_unload = call_original, // listener .on_accepted = libjbxm_on_accepted, .on_error = call_original, .on_disconnect = libjbxm_on_disconnect, // chunk .on_pre_read_chunk = on_pre_read_chunk, .on_OK_read_chunk = on_OK_read_chunk, .on_EOD_read_chunk = call_original, .on_post_read_chunk = call_original, .on_pre_write_chunk = on_pre_write_chunk, .on_OK_write_chunk = call_original, .on_EOD_write_chunk = call_original, .on_post_write_chunk = on_post_write_chunk, }, };
/* transmit a message on the provided connection this function takes the raw data and its length */ EXPORT int xbee_connTx(struct xbee *xbee, struct xbee_con *con, char *data, int length) { int ret = XBEE_ENONE; struct bufData *buf; struct xbee_conType *conType; int waitForAckEnabled; /* check parameters */ if (!xbee) { if (!xbee_default) return XBEE_ENOXBEE; xbee = xbee_default; } if (!xbee_validate(xbee)) return XBEE_ENOXBEE; if (!con) return XBEE_EMISSINGPARAM; /* check the provided connection */ if (_xbee_conValidate(xbee, con, &conType)) return XBEE_EINVAL; /* check that we are able to send the message, if there is no xbee->f->connTx mapping, then we need a conType->txHandler */ if (!conType->txHandler && !xbee->f->connTx) return XBEE_ECANTTX; /* allocate a buffer, 1 byte is already held within the bufData struct, and we don't send the trailing '\0' */ if ((buf = calloc(1, sizeof(struct bufData) + (sizeof(unsigned char) * (length - 1)))) == NULL) { ret = XBEE_ENOMEM; goto die1; } /* populate the buffer */ buf->len = length; memcpy(buf->buf, data, length); /* cache the value of waitForAck, because it may change halfway through! */ waitForAckEnabled = con->options.waitForAck; /* if the connection has 'waitForAck' enabled, then we need to get a free FrameID that can be used */ if (waitForAckEnabled) { /* if we are configured to wait for an Ack, then we need to lock down the connection */ xbee_log(4,"Locking txMutex for con @ %p", con); xsys_mutex_lock(&con->txMutex); if ((con->frameID = xbee_frameIdGet(xbee, con)) == 0) { /* currently we don't inform the user (BAD), but this is unlikely unless you are communicating with >256 remote nodes */ xbee_log(1,"No avaliable frame IDs... we can't validate delivery"); xbee_log(4,"Unlocking txMutex for con @ %p (failed to get FrameID)", con); xsys_mutex_unlock(&con->txMutex); } else { /* mark the FrameID as present */ con->frameID_enabled = 1; } } /* if there is a custom mapping for connTx, then the handlers are skipped (but can be called from within the mapping!) */ if (!xbee->f->connTx) { struct bufData *oBuf; oBuf = buf; /* execute the conType handler, this should take the data provided, and convert it into an XBee formatted block of data this is given, and returned via the 'buf' argument */ xbee_log(6,"Executing handler (%s)...", conType->txHandler->handlerName); if ((ret = conType->txHandler->handler(xbee, conType->txHandler, 0, &buf, con, NULL)) != XBEE_ENONE) goto die2; /* a bit of sanity checking... */ if (!buf || buf == oBuf) { ret = XBEE_EUNKNOWN; goto die2; } free(oBuf); } if (!xbee->f->connTx) { /* if there is no connTx mapped, then add the packet to libxbee's txlist, and prod the tx thread */ ll_add_tail(&xbee->txList, buf); xsys_sem_post(&xbee->txSem); } else { /* same as before, if a mapping is registered, then the packet isn't queued for Tx, at least not here instead we execute the mapped function */ if ((ret = xbee->f->connTx(xbee, con, buf)) != XBEE_ENONE) goto die2; } /* if we should be waiting for an Ack, we now need to wait */ if (waitForAckEnabled && con->frameID) { xbee_log(4,"Waiting for txSem for con @ %p", con); /* the wait occurs inside xbee_frameIdGetACK() */ ret = xbee_frameIdGetACK(xbee, con, con->frameID); if (ret) xbee_log(4,"--- xbee_frameIdGetACK() returned: %d",ret); /* unlock the connection so that other transmitters may follow on */ xbee_log(4,"Unlocking txMutex for con @ %p", con); xsys_mutex_unlock(&con->txMutex); } /* disable the frameID */ con->frameID_enabled = 0; goto done; die2: free(buf); die1: done: return ret; }
/* create a new connection based on the address information provided if a connection already exists with a matching address, *retCon points to it, and XBEE_EEXISTS is returned the userData provided is assigned to the connection immediately */ EXPORT int xbee_conNew(struct xbee *xbee, struct xbee_con **retCon, unsigned char id, struct xbee_conAddress *address, void *userData) { int ret; struct xbee_con *con; struct xbee_conType *conType; /* check parameters */ if (!xbee) { if (!xbee_default) return XBEE_ENOXBEE; xbee = xbee_default; } if (!xbee_validate(xbee)) return XBEE_ENOXBEE; if (!xbee->mode) return XBEE_ENOMODE; if (!retCon) return XBEE_EMISSINGPARAM; if (!address) return XBEE_EMISSINGPARAM; /* get the conType that is being requested */ if (id >= xbee->mode->conTypeCount) return XBEE_EINVAL; conType = &(xbee->mode->conTypes[id]); /* check the addressing information */ switch (conType->needsAddress) { /* don't care */ case 0: break; /* need either */ case 1: if (!address->addr16_enabled && !address->addr64_enabled) return XBEE_EINVAL; break; /* need 16-bit */ case 2: if (!address->addr16_enabled) return XBEE_EINVAL; break; /* need 64-bit */ case 3: if (!address->addr64_enabled) return XBEE_EINVAL; break; /* need both */ case 4: if (!address->addr16_enabled || !address->addr64_enabled) return XBEE_EINVAL; break; /* not supported */ default: xbee_log(1,"addressing mode %d is not supported", conType->needsAddress); return XBEE_EINVAL; } /* retrieve a connection if one aready exists, ignoring sleeping connections */ if ((con = xbee_conFromAddress(xbee, conType, address)) != NULL && !con->sleeping) { *retCon = con; ret = XBEE_EEXISTS; goto done; } ret = XBEE_ENONE; /* allocate the memory */ if ((con = calloc(1, sizeof(struct xbee_con))) == NULL) { ret = XBEE_ENOMEM; goto die1; } /* setup the connection info */ con->conType = conType; memcpy(&con->address, address, sizeof(struct xbee_conAddress)); con->userData = userData; ll_init(&con->rxList); xsys_sem_init(&con->callbackSem); xsys_mutex_init(&con->txMutex); /* this mapping is implemented as an extension, therefore it is entirely optional! */ if (xbee->f->conNew) { int ret; if ((ret = xbee->f->conNew(xbee, retCon, id, address, userData)) != 0) { /* ret should be either 0 / XBEE_ESTALE */; return ret; } } /* once everything has been done, add it to the list (enable it) */ ll_add_tail(&(con->conType->conList), con); *retCon = con; /* log the details */ xbee_log(2,"Created new '%s' connection @ %p", conType->name, con); xbee_conLogAddress(xbee, address); goto done; die1: done: return ret; }
static int on_each_read_record(const struct jbxm_initconf_st* iconf, struct jbxm_callback_if_st* cbif) { assert(iconf); assert(cbif); assert(cbif->type == JBXM_CBT_EACH_RRECORD); assert(cbif->io_area->avail > 0); struct UserData_st* ud = dbGET(cbif, "user-data"); assert(ud); // available cbif->io_area->buff[0 to cbif->io_area->avail] + '\0' if (ud->bodylen) { // ヘッダの取得は終了し、Content-Length の指定があるので溜め込む struct varmem_st* vm = new_varmem((size_t)cbif->io_area->avail); assert(vm); memcpy(vm->bytes, cbif->io_area->buff, (size_t)cbif->io_area->avail); void* ok = ll_add_tail(ud->body_chunks, vm); assert(ok); ud->body_chunks_sumlen += (size_t)cbif->io_area->avail; return 0; } // HTTP ヘッダの収集 char* buff = (char*)cbif->io_area->buff; ljbx_chomp(buff); // [if buff is string] PRINT("read [%.*s]", (int)cbif->io_area->avail, buff); if (! *buff) { // 空行 if (! ud->method) { // リクエストが設定されていない間は無視 return 0; } //PRINT("headers\n--->>"); //hm_foreach(ud->headers, print_header_, NULL); //PRINT("\n---<<"); const char* clen = hm_get(ud->headers, "content-length"); if (clen) { // add check digit !! const int bodylen = atoi(clen); if (bodylen > 0) { // BODY を収集する ud->bodylen = (size_t)bodylen; } else { if (bodylen) { // bodylen < 0 ud->response = http_CreateError(400); } else { // bodylen == 0 ud->response = http_CreateResponse(ud); } } } else { ud->response = http_CreateResponse(ud); } if (ud->response) { cbif->flow->next_events = EPOLLOUT | EPOLLET; } return 0; } if (ud->method) { // リクエストは解決しているので残りは ud->headers に追加 char* key = NULL; char* val = NULL; int ns = sscanf(buff, "%m[^:]: %m[^\r\n]", &key, &val); if (ns == 2) { ljbx_strtolower(key); void* old_val = NULL; hm_set(ud->headers, key, val, &old_val); free(old_val); // 重複は後勝ち } else { free(val); } free(key); } else { // リクエストを解決 char* method = NULL; char* path = NULL; int major = 0; int minor = 0; int ns = sscanf(buff, "%m[A-Z] %ms HTTP/%d.%d", &method, &path, &major, &minor); if (ns < 2) { free(method); free(path); ud->response = http_CreateError(400); cbif->flow->next_events = EPOLLOUT | EPOLLET; return 0; } ud->method = method; ud->path = path; ud->version.major = major; ud->version.minor = minor; } // set cbif->flow->next_events if necessary return 0; }