Exemple #1
0
xbee_err xbee_pktAlloc(struct xbee_pkt **nPkt, struct xbee_pkt *oPkt, int dataLen) {
	size_t memSize;
	struct xbee_pkt *pkt;
	xbee_err ret;
	
	if (!nPkt) return XBEE_EMISSINGPARAM;
	
	if (oPkt) {
		if ((ret = xbee_ll_ext_item(pktList, oPkt)) != XBEE_ENONE) {
			return ret;
		}
	}
	
	memSize = sizeof(*pkt);
	memSize += sizeof(char) * dataLen;
	
	if (!(pkt = realloc(oPkt, memSize))) return XBEE_ENOMEM;
	
	if (!oPkt) {
		memset(pkt, 0, memSize);
		pkt->dataItems = xbee_ll_alloc();
	}
	
	if ((ret = xbee_ll_add_tail(pktList, pkt)) != XBEE_ENONE) {
		_xbee_pktFree(pkt);
		ret = XBEE_ELINKEDLIST;
	} else {
		*nPkt = pkt;
	}
	
	return ret;
}
Exemple #2
0
static xbee_err _xbee_pktFree(struct xbee_pkt *pkt) {
	xbee_ll_ext_item(pktList, pkt);
	
	xbee_ll_free(pkt->dataItems, (void(*)(void *))_xbee_pktDataKeyDestroy);
	
	free(pkt);
	
	return XBEE_ENONE;
}
Exemple #3
0
EXPORT xbee_err xbee_shutdown(struct xbee *xbee) {
	if (!xbee) return XBEE_EMISSINGPARAM;
#ifndef XBEE_DISABLE_STRICT_OBJECTS
	if (xbee_validate(xbee) != XBEE_ENONE) return XBEE_EINVAL;
#endif /* XBEE_DISABLE_STRICT_OBJECTS */

	/* pluck out the instance - from now on it is invalid */
	xbee_ll_ext_item(xbeeList, xbee);
	/* start a detached thread */
	xbee_threadStart(xbee, NULL, -1, 1, xbee_shutdownThread, (void*)(xsys_thread_self()));
	
	return XBEE_ENONE;
}
Exemple #4
0
xbee_err xbee_free(struct xbee *xbee) {
	int i;

	xbee_ll_ext_item(xbeeList, xbee);
	xbee->die = 1;
	
	if (xbee->iface.rx) {
		xsys_sem_post(&xbee->iface.rx->sem);
	}
	if (xbee->iface.tx) {
		xsys_sem_post(&xbee->iface.tx->sem);
	}
	
	/* sleep for 4 seconds because:
	     the rx thread should timeout every 2-ish econds
	     the rxHandler thread will need to run round one more time to clean up
	     the tx thread will need to run round one more time to clean up */
	for (i = 0; i < 4; i++) usleep(1000000);
	
	xbee_threadDestroyMine(xbee);
	
	if (xbee->netInfo) xbee_netStop(xbee);
	
	if (xbee->mode && xbee->mode->shutdown) xbee->mode->shutdown(xbee);
	
	xbee_modeCleanup(xbee->iface.conTypes);
	xbee_rxFree(xbee->iface.rx);
	xbee_txFree(xbee->iface.tx);
#ifndef XBEE_DISABLE_LOGGING
	xbee_logFree(xbee->log);
#endif /* !XBEE_DISABLE_LOGGING */
	xbee_frameBlockFree(xbee->fBlock);
	
	free(xbee);
	
	return XBEE_ENONE;
}
Exemple #5
0
xbee_err xbee_rxHandler(struct xbee *xbee, int *restart, void *arg) {
	xbee_err ret;
	struct xbee_rxInfo *info;
	struct xbee_tbuf *buf;
	
	struct xbee_modeConType *conType;
	
	struct xbee_frameInfo frameInfo;
	struct xbee_conAddress address;
	struct xbee_pkt *pkt;
	
	struct xbee_con *con;
	
	ret = XBEE_ENONE;
	info = arg;
	buf = NULL;
	
	if (!info->bufList) {
		*restart = 0;
		return XBEE_EINVAL;
	}
	
	memset(&frameInfo, 0, sizeof(frameInfo));
	conType = NULL;
	while (!xbee->die) {
		/* this is here so that it will be triggered AFTER the packet has been queued (assuming a packet needed to be queued)
		   handle any frame info (prod someone who may be waiting for ACK/NAK/etc...) */
		if (info->fBlock && frameInfo.active != 0 && conType && conType->allowFrameId != 0) {
			xbee_log(20, "received Tx status (block: %p, frame: 0x%02X, status: 0x%02X)", info->fBlock, frameInfo.id, frameInfo.retVal);
			if ((ret = xbee_framePost(info->fBlock, frameInfo.id, frameInfo.retVal)) != XBEE_ENONE) {
				xbee_log(2, "failed to respond to frame (block: %p, frame: 0x%02X)... xbee_framePost() returned %d", info->fBlock, frameInfo.id, ret);
				ret = XBEE_ENONE;
			}
		}
		
		xsys_sem_wait(&info->sem);
		
		/* get the next buffer */
		if ((ret = xbee_ll_ext_head(info->bufList, (void**)&buf)) != XBEE_ENONE && ret != XBEE_ERANGE) return XBEE_ELINKEDLIST;
		ret = XBEE_ENONE;
		if (!buf) continue;
		
		/* check we actually have some data to work with... */
		if (buf->len < 1) goto done;
		
		/* locate the connection type of this buffer */
		if ((ret = xbee_modeLocateConType(*info->conTypes, 1, NULL, &buf->data[0], NULL, &conType)) == XBEE_ENOTEXISTS || !conType) {
			xbee_log(4, "Unknown message type recieved... (0x%02X)", buf->data[0]);
			goto done;
		} else if (ret != XBEE_ENONE) {
			/* some other error occured */
			break;
		}
		
		/* prepare the buckets */
		memset(&frameInfo, 0, sizeof(frameInfo));
		memset(&address, 0, sizeof(address));
		pkt = NULL;
		
		/* process the buffer into the buckets */
		if ((ret = conType->rxHandler->func(xbee, info->handlerArg, conType->rxHandler->identifier, buf, &frameInfo, &address, &pkt)) != XBEE_ENONE) break;
		
		/* its possible that the buffer ONLY contained frame information... if so, were done! */
		if (!pkt) goto done;
		
		memcpy(&pkt->address, &address, sizeof(address));
		pkt->conType = conType->name;
		pkt->apiIdentifier = buf->data[0];
		
		if (info->fBlock && frameInfo.active != 0 && conType && conType->allowFrameId != 0) {
			pkt->frameId = frameInfo.id;
		}

		/* if the packet handler didn't fill in the timestamp, then we should do it here */
		if (pkt->timestamp.tv_sec == 0 && pkt->timestamp.tv_nsec == 0) {
			memcpy(&pkt->timestamp, &buf->ts, sizeof(buf->ts));
		}
		
		xbee_log(12, "received '%s' type packet with %d bytes of data...", conType->name, pkt->dataLen);
		
		/* match the address to a connection */
		if (((ret = xbee_conLocate(conType->conList, &address, &con, CON_SNOOZE)) != XBEE_ENONE &&
		      ret != XBEE_ESLEEPING &&
		      ret != XBEE_ECATCHALL) ||
		    !con) {
			xbee_pktFree(pkt);
			if (ret == XBEE_ENOTEXISTS) {
				xbee_log(5, "connectionless '%s' packet (%d bytes)...", conType->name, buf->len);
				xbee_conLogAddress(xbee, 10, &address);
				goto done;
			}
			xbee_log(1, "xbee_conLocate() returned %d...", ret);
			break;
		}
		
		xbee_log(15, "matched packet with con @ %p", con);
		xbee_conLogAddress(xbee, 16, &address);
		
		if (conType->rxHandler->funcPost) {
			xbee_err ret;
			if ((ret = conType->rxHandler->funcPost(xbee, con, pkt)) != XBEE_ENONE) {
				xbee_log(1, "funcPost() failed for con @ %p - returned %d\n", con, ret);
			}
		}
		
		/* wake the connection if necessary */
		if (con->sleepState != CON_AWAKE) {
			con->sleepState = CON_AWAKE;
			xbee_log(1, "woke connection @ %p", con);
		}
		
		con->info.countRx++;
		con->info.lastRxTime = time(NULL);
		
		if (!con->settings.catchAll) {
			if (address.addr16_enabled && !con->address.addr16_enabled && conType->save_addr16) {
				if (conType->addressTest(address.addr16, sizeof(address.addr16)) == XBEE_ENONE) {
					con->address.addr16_enabled = 1;
					memcpy(con->address.addr16, address.addr16, 2);
				}
			}
			if (address.addr64_enabled && !con->address.addr64_enabled && conType->save_addr64) {
				if (conType->addressTest(address.addr64, sizeof(address.addr64)) == XBEE_ENONE) {
					con->address.addr64_enabled = 1;
					memcpy(con->address.addr64, address.addr64, 8);
				}
			}
		}
		
		/* add the packet to the connection's tail! */
		if ((ret = xbee_conLinkPacket(con, pkt)) != XBEE_ENONE) {
			xbee_log(1, "failed to store packet with connection... xbee_conLinkPacket() returned %d", ret);
			break;
		}
		
done:
		xbee_ll_ext_item(needsFree, buf);
		free(buf);
		buf = NULL;
	}
	
	if (buf) {
		xbee_ll_ext_item(needsFree, buf);
		free(buf);
	}
	
	if (xbee->die && ret == XBEE_ENONE) return XBEE_ESHUTDOWN;
	return ret;
}
Exemple #6
0
xbee_err xbee_netRx(struct xbee *xbee, void *arg, struct xbee_tbuf **buf) {
    char c;
    char length[2];
    int pos, len, ret;
    struct xbee_tbuf *iBuf;
    int fd;

    if (!xbee || !buf) return XBEE_EMISSINGPARAM;

    if (arg) {
        /* this is on the server end */
        struct xbee_netClientInfo *info;
        info = arg;
        if (xbee != info->xbee) return XBEE_EINVAL;
        fd = info->fd;
    } else {
        /* this is on the client end */
        struct xbee_modeData *info;
        info = xbee->modeData;
        fd = info->netInfo.fd;
    }

    while (1) {
        do {
            if ((ret = recv(fd, &c, 1, MSG_NOSIGNAL)) < 0) return XBEE_EIO;
            if (ret == 0) goto eof;
        } while (c != 0x7E);

        for (len = 2, pos = 0; pos < len; pos += ret) {
            ret = recv(fd, &(length[pos]), len - pos, MSG_NOSIGNAL);
            if (ret > 0) continue;
            if (ret == 0) goto eof;
            return XBEE_EIO;
        }

        len = (((length[0] << 8) & 0xFF00) | (length[1] & 0xFF)) + 1;
        if ((iBuf = malloc(sizeof(*iBuf) + len)) == NULL) return XBEE_ENOMEM;
        xbee_ll_add_tail(needsFree, iBuf);

        iBuf->len = len;

        memset(&iBuf->ts, 0, sizeof(iBuf->ts));

        for (pos = 0; pos < iBuf->len; pos += ret) {
            ret = recv(fd, &(iBuf->data[pos]), iBuf->len - pos, MSG_NOSIGNAL);
            if (ret > 0) continue;
            xbee_ll_ext_item(needsFree, iBuf);
            free(iBuf);
            if (ret == 0) goto eof;
            return XBEE_EIO;
        }
        break;
    }

    /* needs free is handled for us by xbee_rxHandler(), we just need to register it */
    *buf = iBuf;

    return XBEE_ENONE;
eof:
    if (arg) {
        struct xbee_netClientInfo *info;
#ifndef XBEE_NO_NET_SERVER
        struct xbee_netClientInfo *deadClient;
#endif
        struct xbee_con *con;
        info = arg;

#ifndef XBEE_NO_NET_SERVER
        /* tidy up any dead clients - not including us */
        while (xbee_ll_ext_head(netDeadClientList, (void**)&deadClient) == XBEE_ENONE && deadClient != NULL) {
            xbee_netClientShutdown(deadClient);
        }

        /* xbee_netRx() is responsible for free()ing memory and killing off client threads on the server
           to do this, we need to add ourselves to the netDeadClientList, and remove ourselves from the clientList
           the server thread will then cleanup any clients on the next accept() */
        xbee_ll_add_tail(netDeadClientList, arg);
        xbee_ll_ext_item(xbee->netInfo->clientList, arg);
#endif /* XBEE_NO_NET_SERVER */

        /* kill the other threads */
        /* excluding the rx thread... thats us! */
        if (info->rxHandlerThread) {
            xbee_threadKillJoin(info->xbee, info->rxHandlerThread, NULL);
            info->rxHandlerThread = NULL;
        }
        if (info->txThread) {
            xbee_threadKillJoin(info->xbee, info->txThread, NULL);
            info->txThread = NULL;
        }

        /* close up the socket */
        shutdown(info->fd, SHUT_RDWR);
        xsys_close(info->fd);
        info->fd = -1; /* <-- mark it closed */

        /* end all of our connections */
        for (con = NULL; xbee_ll_ext_head(info->conList, (void **)&con) == XBEE_ENONE && con; ) {
            xbee_conEnd(con);
        }

        /* this leaves us with a call to xbee_threadKillJoin() and xbee_netClientFree() left! */
    }
    return XBEE_EEOF;
}