Ejemplo n.º 1
0
/**
 * 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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
/* 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;
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
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;
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
0
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,
	},
};
Ejemplo n.º 8
0
/* 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;
}
Ejemplo n.º 9
0
/* 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;
}
Ejemplo n.º 10
0
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;
}