Merge branch 'dev'
This commit is contained in:
+119
-3
@@ -17,57 +17,173 @@ enum UC_MBUF_FLAGS {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct MBuf {
|
struct MBuf {
|
||||||
|
/** prev/next pointer, user can use this for a linked list*/
|
||||||
|
struct MBuf *prev;
|
||||||
struct MBuf *next;
|
struct MBuf *next;
|
||||||
|
/** Pointers the user can use to remember spots in
|
||||||
|
* the data. (these must either be NULL pointers or point into
|
||||||
|
* something in the buffer*/
|
||||||
uint8_t *p1;
|
uint8_t *p1;
|
||||||
uint8_t *p2;
|
uint8_t *p2;
|
||||||
uint8_t *p3;
|
uint8_t *p3;
|
||||||
uint8_t *p4;
|
uint8_t *p4;
|
||||||
|
/**Arbitary pointer user can associate with the mbuf*/
|
||||||
void *cookie;
|
void *cookie;
|
||||||
|
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
|
/** Total no of bytes from bufstart*/
|
||||||
uint32_t allocated;
|
uint32_t allocated;
|
||||||
|
/** Start of the buffer*/
|
||||||
uint8_t *bufstart;
|
uint8_t *bufstart;
|
||||||
|
/** Start of the data in the buffer*/
|
||||||
uint8_t *head;
|
uint8_t *head;
|
||||||
|
/** End of the buffer (one byte past the data) */
|
||||||
uint8_t *tail;
|
uint8_t *tail;
|
||||||
|
/** Internal data, if we allocate it inline */
|
||||||
uint8_t inline_data[0];
|
uint8_t inline_data[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Conventions:
|
/**
|
||||||
|
* Concept:
|
||||||
|
* <--------- allocated ----------->
|
||||||
|
* <--- len -->
|
||||||
|
* +--------------------------------+
|
||||||
|
* |Headroom| Data |Tailroom |
|
||||||
|
* +--------------------------------+
|
||||||
|
* ^ ^ ^
|
||||||
|
* | | |
|
||||||
|
* | | tail
|
||||||
|
* | head
|
||||||
|
* bufstart
|
||||||
|
*
|
||||||
|
* Initially when empty, head == tail, and the length is 0.
|
||||||
|
* Data is added to the tail.
|
||||||
|
*
|
||||||
|
* If head == bufstart, there is no headroom
|
||||||
|
* if tail points one past the allocated space, there is no
|
||||||
|
* tailroom (the buffer is full)
|
||||||
|
*
|
||||||
|
* Conventions:
|
||||||
* push - prepend data to the buffer (in the head room part)
|
* push - prepend data to the buffer (in the head room part)
|
||||||
|
* (move head to the left)
|
||||||
* pull - remove data from the beginning of the message.
|
* pull - remove data from the beginning of the message.
|
||||||
|
* (move head to the right)
|
||||||
* put - Add data to the buffer.
|
* put - Add data to the buffer.
|
||||||
|
* (move tail to the right)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Allocate an mbuf with a length and headroom,
|
||||||
|
* the buffer will have the flag UC_MBUF_FL_MALLOC
|
||||||
|
* The total length of the buffer will be length+headroom
|
||||||
|
*
|
||||||
|
* @param len the initial length of the mbuf
|
||||||
|
* @param the initial headroom of the mbuf
|
||||||
|
* @return NULL if the allocation fails
|
||||||
*/
|
*/
|
||||||
struct MBuf *uc_mbuf_new_hr(uint32_t len, uint32_t headroom);
|
struct MBuf *uc_mbuf_new_hr(uint32_t len, uint32_t headroom);
|
||||||
|
|
||||||
|
/** As uc_mbuf_new_hr, but without any headroom*/
|
||||||
#define uc_mbuf_new(len) uc_mbuf_new_hr((len), 0)
|
#define uc_mbuf_new(len) uc_mbuf_new_hr((len), 0)
|
||||||
|
|
||||||
|
|
||||||
|
/** Allocate an mbuf with a length and headroom,
|
||||||
|
* the buffer will have the flag UC_MBUF_FL_MALLOC_INLINE
|
||||||
|
* The total length of the buffer will be length+headroom
|
||||||
|
*
|
||||||
|
* @param len the initial length of the mbuf
|
||||||
|
* @param the initial headroom of the mbuf
|
||||||
|
* @return NULL if the allocation fails
|
||||||
|
*/
|
||||||
struct MBuf *uc_mbuf_new_inline_hr(uint32_t len, uint32_t headroom);
|
struct MBuf *uc_mbuf_new_inline_hr(uint32_t len, uint32_t headroom);
|
||||||
|
|
||||||
|
/** As uc_mbuf_new_inline_hr, but without any headroom*/
|
||||||
#define uc_mbuf_new_inline(len) uc_mbuf_new_inline_hr((len), 0)
|
#define uc_mbuf_new_inline(len) uc_mbuf_new_inline_hr((len), 0)
|
||||||
|
|
||||||
|
/** @param mbuf the mbuf to free. (passing NULL is a no-op)*/
|
||||||
void uc_mbuf_free(struct MBuf *mbuf);
|
void uc_mbuf_free(struct MBuf *mbuf);
|
||||||
|
|
||||||
|
/** Create a new mbuf, with a copy of the data from the given
|
||||||
|
* mbuf. The new mbuf will have the same headroom as the old one,
|
||||||
|
* but no tailroom.
|
||||||
|
*
|
||||||
|
* @param mbuf mbuf to copy
|
||||||
|
*/
|
||||||
struct MBuf *uc_mbuf_copy_data(struct MBuf *mbuf);
|
struct MBuf *uc_mbuf_copy_data(struct MBuf *mbuf);
|
||||||
|
|
||||||
|
/** Initialize an mbuf. This function is mostly used internally,
|
||||||
|
* but can be used to e.g. create an mbuf based on a local array
|
||||||
|
* (in which case UC_MBUF_FL_STATIC must be set), or other data
|
||||||
|
* whose memory is already allocated.
|
||||||
|
*
|
||||||
|
* The whole buffer must have len + headroom available data
|
||||||
|
*
|
||||||
|
* @param mbuf to initialise
|
||||||
|
* @param buf start of the buffer
|
||||||
|
* @param len length of the buffer (not including the headroom)
|
||||||
|
* @param headroom the headroom in the buffer
|
||||||
|
* @param flags The appropriate UC_MBUF_FLAGS
|
||||||
|
*/
|
||||||
void uc_mbuf_init(struct MBuf *mbuf, uint8_t *buf, uint32_t len, uint32_t headroom, uint32_t flags);
|
void uc_mbuf_init(struct MBuf *mbuf, uint8_t *buf, uint32_t len, uint32_t headroom, uint32_t flags);
|
||||||
void uc_mbuf_zero(struct MBuf *mbuf);
|
|
||||||
void uc_mbuf_reset(struct MBuf *mbuf);
|
|
||||||
|
|
||||||
|
/** Zero out all the data in this mbuf, including the headroom
|
||||||
|
*
|
||||||
|
* @param mbuf mbuf to zero out
|
||||||
|
*/
|
||||||
|
void uc_mbuf_zero(struct MBuf *mbuf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the length of the data in this mbuf
|
||||||
|
*/
|
||||||
static UC_INLINE uint32_t uc_mbuf_len(struct MBuf *mbuf)
|
static UC_INLINE uint32_t uc_mbuf_len(struct MBuf *mbuf)
|
||||||
{
|
{
|
||||||
return (uint32_t)(mbuf->tail - mbuf->head);
|
return (uint32_t)(mbuf->tail - mbuf->head);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the length of the tailroom in this mbuf
|
||||||
|
*/
|
||||||
static UC_INLINE uint32_t uc_mbuf_tailroom(struct MBuf *mbuf)
|
static UC_INLINE uint32_t uc_mbuf_tailroom(struct MBuf *mbuf)
|
||||||
{
|
{
|
||||||
return mbuf->allocated - (uint32_t)(mbuf->tail - mbuf->bufstart);
|
return mbuf->allocated - (uint32_t)(mbuf->tail - mbuf->bufstart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the length of the headroom in this mbuf
|
||||||
|
*/
|
||||||
static inline uint32_t uc_mbuf_headroom(struct MBuf *mbuf)
|
static inline uint32_t uc_mbuf_headroom(struct MBuf *mbuf)
|
||||||
{
|
{
|
||||||
return (uint32_t)(mbuf->head - mbuf->bufstart);
|
return (uint32_t)(mbuf->head - mbuf->bufstart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Append data data to this buffer
|
||||||
|
* The returned pointer points at the end of the current
|
||||||
|
* data in the buffer, advancing the tail be size bytes .
|
||||||
|
* You need to insert the size bytes at in the returned pointer.
|
||||||
|
*
|
||||||
|
* @param size bytes to put in the buffer
|
||||||
|
* @return NULL if the mbuf does not have room for the given size
|
||||||
|
*/
|
||||||
uint8_t *uc_mbuf_put(struct MBuf *mbuf, uint32_t size);
|
uint8_t *uc_mbuf_put(struct MBuf *mbuf, uint32_t size);
|
||||||
|
|
||||||
|
/** Prepend data to the buffer. The buffer needs to have enough
|
||||||
|
* headroom to allow this.
|
||||||
|
* The returned pointer points size bytes in front if the current
|
||||||
|
* data in the buffer, retreating the head pointer by size butes
|
||||||
|
* You need to insert the size bytes in the returned pointer.
|
||||||
|
*
|
||||||
|
* @oaram size bytes to prepend to the buffer
|
||||||
|
* @return NULL if the mbuf does not have enough headroom
|
||||||
|
*/
|
||||||
uint8_t *uc_mbuf_push(struct MBuf *mbuf, uint32_t size);
|
uint8_t *uc_mbuf_push(struct MBuf *mbuf, uint32_t size);
|
||||||
|
|
||||||
|
/** Remove data from the buffer ("read" data from it)
|
||||||
|
* The returned pointer is the beginning of the data in the
|
||||||
|
* buffer, advancing the head by size bytes.
|
||||||
|
*
|
||||||
|
* @param size number of bytes to pull
|
||||||
|
* @return NULL if the buffer does not have at least size bytes
|
||||||
|
**/
|
||||||
uint8_t *uc_mbuf_pull(struct MBuf *mbuf, uint32_t size);
|
uint8_t *uc_mbuf_pull(struct MBuf *mbuf, uint32_t size);
|
||||||
|
|
||||||
#undef UC_INLINE
|
#undef UC_INLINE
|
||||||
|
|||||||
@@ -83,6 +83,18 @@ void uc_strv_clear(struct UCStrv *strv);
|
|||||||
*/
|
*/
|
||||||
void uc_strv_destroy(struct UCStrv *strv);
|
void uc_strv_destroy(struct UCStrv *strv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append all the elments from b to a
|
||||||
|
* If copy is 1, the appended elements will be copied when appended
|
||||||
|
*
|
||||||
|
* @param a destination UCStrv
|
||||||
|
* @param b source UCStrv
|
||||||
|
* @param copy 1 for making a copy of the string when appending it
|
||||||
|
* 0 to just append the same pointer in b to a
|
||||||
|
* @return 0 on success, != 0 if appending/allocation fails
|
||||||
|
*/
|
||||||
|
int uc_strv_append_all(struct UCStrv *a, struct UCStrv *b, int copy);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -46,14 +46,14 @@
|
|||||||
//a 'zap' member inside a struct foo.
|
//a 'zap' member inside a struct foo.
|
||||||
//give us the struct foo*:
|
//give us the struct foo*:
|
||||||
//struct foo *f = CONTAINER_OF(p, struct foo, zap);
|
//struct foo *f = CONTAINER_OF(p, struct foo, zap);
|
||||||
#define CONTAINER_OF(ptr, type, member) ({ \
|
#define UC_CONTAINER_OF(ptr, type, member) ({ \
|
||||||
typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||||
(type *)((void *)(unsigned char *)__mptr - offsetof(type, member) ); })
|
(type *)((void *)(unsigned char *)__mptr - offsetof(type, member) ); })
|
||||||
|
|
||||||
//the void* cast is to suppress alignment warnings
|
//the void* cast is to suppress alignment warnings
|
||||||
|
|
||||||
//Same as CONTAINER_OF, but for a const pointer to avoid gcc warnings..
|
//Same as UC_CONTAINER_OF, but for a const pointer to avoid gcc warnings..
|
||||||
#define CONST_CONTAINER_OF(ptr, type, member) ({ \
|
#define UC_CONST_CONTAINER_OF(ptr, type, member) ({ \
|
||||||
const typeof( ((const type *)0)->member ) *__mptr = (ptr); \
|
const typeof( ((const type *)0)->member ) *__mptr = (ptr); \
|
||||||
(const type *)((const void *)(const unsigned char *)__mptr - offsetof(const type, member) ); })
|
(const type *)((const void *)(const unsigned char *)__mptr - offsetof(const type, member) ); })
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -32,7 +32,7 @@ static void uc_cached_clock_now(struct UCoreClock *uclock,
|
|||||||
struct timeval *tv)
|
struct timeval *tv)
|
||||||
{
|
{
|
||||||
struct UCoreCachedClock *cached_clock;
|
struct UCoreCachedClock *cached_clock;
|
||||||
cached_clock = CONTAINER_OF(uclock, struct UCoreCachedClock, clock),
|
cached_clock = UC_CONTAINER_OF(uclock, struct UCoreCachedClock, clock),
|
||||||
|
|
||||||
*tv = cached_clock->cache;
|
*tv = cached_clock->cache;
|
||||||
}
|
}
|
||||||
@@ -55,7 +55,7 @@ void uc_cached_clock_update(struct UCoreCachedClock *uclock)
|
|||||||
static void uc_settable_clock_now(struct UCoreClock *uclock, struct timeval *tv)
|
static void uc_settable_clock_now(struct UCoreClock *uclock, struct timeval *tv)
|
||||||
{
|
{
|
||||||
struct UCoreSettableClock *cached_clock;
|
struct UCoreSettableClock *cached_clock;
|
||||||
cached_clock = CONTAINER_OF(uclock, struct UCoreSettableClock, clock),
|
cached_clock = UC_CONTAINER_OF(uclock, struct UCoreSettableClock, clock),
|
||||||
|
|
||||||
*tv = cached_clock->now;
|
*tv = cached_clock->now;
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-5
@@ -86,11 +86,13 @@ struct MBuf *uc_mbuf_new_inline_hr(uint32_t len, uint32_t headroom)
|
|||||||
|
|
||||||
void uc_mbuf_free(struct MBuf *mbuf)
|
void uc_mbuf_free(struct MBuf *mbuf)
|
||||||
{
|
{
|
||||||
if (mbuf->flags & (UC_MBUF_FL_MALLOC | UC_MBUF_FL_MALLOC_BUF))
|
if (mbuf != NULL) {
|
||||||
free(mbuf->bufstart);
|
if (mbuf->flags & (UC_MBUF_FL_MALLOC | UC_MBUF_FL_MALLOC_BUF))
|
||||||
|
free(mbuf->bufstart);
|
||||||
if (mbuf->flags & (UC_MBUF_FL_MALLOC | UC_MBUF_FL_MALLOC_INLINE))
|
|
||||||
free(mbuf);
|
if (mbuf->flags & (UC_MBUF_FL_MALLOC | UC_MBUF_FL_MALLOC_INLINE))
|
||||||
|
free(mbuf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void uc_mbuf_zero(struct MBuf *mbuf)
|
void uc_mbuf_zero(struct MBuf *mbuf)
|
||||||
|
|||||||
+27
-2
@@ -29,7 +29,8 @@ int uc_strv_expand(struct UCStrv *strv)
|
|||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if (strv->cnt >= strv->allocated) {
|
if (strv->cnt >= strv->allocated) {
|
||||||
rc = uc_strv_grow(strv, 1);
|
//make some extra room
|
||||||
|
rc = uc_strv_grow(strv, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@@ -81,7 +82,6 @@ int uc_strv_null_terminate(struct UCStrv *strv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
strv->strings[strv->cnt] = NULL;
|
strv->strings[strv->cnt] = NULL;
|
||||||
strv->cnt++;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -105,3 +105,28 @@ void uc_strv_destroy(struct UCStrv *strv)
|
|||||||
strv->strings = NULL;
|
strv->strings = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int uc_strv_append_all(struct UCStrv *a, struct UCStrv *b, int copy)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = uc_strv_grow(a, a->allocated + b->cnt);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < b->cnt; i++) {
|
||||||
|
if (copy) {
|
||||||
|
rc = uc_strv_append(a, b->strings[i]);
|
||||||
|
} else {
|
||||||
|
rc = uc_strv_append_nocopy(a, b->strings[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-7
@@ -57,7 +57,9 @@ int uc_thread_queue_init(struct uc_threadqueue *queue, long max_elements)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int uc_thread_queue_tryadd(struct uc_threadqueue *queue, const struct timespec *timeout, struct uc_threadmsg *msg)
|
int uc_thread_queue_tryadd(struct uc_threadqueue *queue,
|
||||||
|
const struct timespec *timeout,
|
||||||
|
struct uc_threadmsg *msg)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct timespec abstimeout;
|
struct timespec abstimeout;
|
||||||
@@ -81,7 +83,8 @@ int uc_thread_queue_tryadd(struct uc_threadqueue *queue, const struct timespec *
|
|||||||
if(timeout->tv_sec == 0 && timeout->tv_nsec == 0) {
|
if(timeout->tv_sec == 0 && timeout->tv_nsec == 0) {
|
||||||
rc = ETIMEDOUT;
|
rc = ETIMEDOUT;
|
||||||
} else {
|
} else {
|
||||||
rc = pthread_cond_timedwait(&queue->write_cond, &queue->mutex, &abstimeout);
|
rc = pthread_cond_timedwait(&queue->write_cond, &queue->mutex,
|
||||||
|
&abstimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -127,7 +130,9 @@ int uc_thread_queue_tryadd(struct uc_threadqueue *queue, const struct timespec *
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int uc_thread_queue_tryget(struct uc_threadqueue *queue, const struct timespec *timeout, struct uc_threadmsg **msg)
|
int uc_thread_queue_tryget(struct uc_threadqueue *queue,
|
||||||
|
const struct timespec *timeout,
|
||||||
|
struct uc_threadmsg **msg)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct timespec abstimeout;
|
struct timespec abstimeout;
|
||||||
@@ -153,7 +158,8 @@ int uc_thread_queue_tryget(struct uc_threadqueue *queue, const struct timespec *
|
|||||||
if(timeout->tv_sec == 0 && timeout->tv_nsec == 0) {
|
if(timeout->tv_sec == 0 && timeout->tv_nsec == 0) {
|
||||||
rc = ETIMEDOUT;
|
rc = ETIMEDOUT;
|
||||||
} else {
|
} else {
|
||||||
rc = pthread_cond_timedwait(&queue->read_cond, &queue->mutex, &abstimeout);
|
rc = pthread_cond_timedwait(&queue->read_cond, &queue->mutex,
|
||||||
|
&abstimeout);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pthread_cond_wait(&queue->read_cond, &queue->mutex);
|
pthread_cond_wait(&queue->read_cond, &queue->mutex);
|
||||||
@@ -192,17 +198,20 @@ int uc_thread_queue_tryget(struct uc_threadqueue *queue, const struct timespec *
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uc_thread_queue_walk_unlocked(struct uc_threadqueue *queue, uc_thread_queue_walk_func walk_func)
|
static void uc_thread_queue_walk_unlocked(struct uc_threadqueue *queue,
|
||||||
|
uc_thread_queue_walk_func walk_func)
|
||||||
{
|
{
|
||||||
struct uc_threadmsg *p;
|
struct uc_threadmsg *p;
|
||||||
struct uc_threadmsg *next;
|
struct uc_threadmsg *next;
|
||||||
|
|
||||||
for(p = queue->first; p; p = next) {
|
for(p = queue->first; p; p = next) {
|
||||||
next = p->next;
|
next = p->next;
|
||||||
walk_func(p);
|
walk_func(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int uc_thread_queue_walk(struct uc_threadqueue *queue, uc_thread_queue_walk_func walk_func)
|
int uc_thread_queue_walk(struct uc_threadqueue *queue,
|
||||||
|
uc_thread_queue_walk_func walk_func)
|
||||||
{
|
{
|
||||||
if (queue == NULL || !walk_func) {
|
if (queue == NULL || !walk_func) {
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
@@ -217,7 +226,8 @@ int uc_thread_queue_walk(struct uc_threadqueue *queue, uc_thread_queue_walk_func
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int uc_thread_queue_destroy(struct uc_threadqueue *queue, uc_thread_queue_walk_func free_func)
|
int uc_thread_queue_destroy(struct uc_threadqueue *queue,
|
||||||
|
uc_thread_queue_walk_func free_func)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
static int timers_cmp(const RBNode *a_, const RBNode *b_)
|
static int timers_cmp(const RBNode *a_, const RBNode *b_)
|
||||||
{
|
{
|
||||||
const struct UCTimer *a = CONST_CONTAINER_OF(a_, struct UCTimer, rb_node);
|
const struct UCTimer *a = UC_CONST_CONTAINER_OF(a_, struct UCTimer, rb_node);
|
||||||
const struct UCTimer *b = CONST_CONTAINER_OF(b_, struct UCTimer, rb_node);
|
const struct UCTimer *b = UC_CONST_CONTAINER_OF(b_, struct UCTimer, rb_node);
|
||||||
|
|
||||||
if (timercmp(&a->timeout, &b->timeout, <)) {
|
if (timercmp(&a->timeout, &b->timeout, <)) {
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@@ -0,0 +1,146 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ortp/ortp.h>
|
||||||
|
#include <ucore/iomux.h>
|
||||||
|
#include <ucore/utils.h>
|
||||||
|
#include <ucore/string.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct IOMux *mux;
|
||||||
|
|
||||||
|
#define errx(x, ...) do { fprintf(stderr, x, __VA_ARGS__); exit(1); } while(0)
|
||||||
|
|
||||||
|
struct RTPSender {
|
||||||
|
FILE *file;
|
||||||
|
char remote_ip[48];
|
||||||
|
uint16_t remote_port;
|
||||||
|
struct UCTimer timer;
|
||||||
|
uint32_t ts;
|
||||||
|
struct timespec last_ts;
|
||||||
|
RtpSession *rtp_sess;
|
||||||
|
RtpProfile *rtp_profile;
|
||||||
|
int accum_diff;
|
||||||
|
uint8_t frame[160];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//returns microsec
|
||||||
|
int diffts(const struct timespec *a, struct timespec *b)
|
||||||
|
{
|
||||||
|
struct timespec diff;
|
||||||
|
diff.tv_sec = b->tv_sec - a->tv_sec;
|
||||||
|
diff.tv_nsec = b->tv_nsec - a->tv_nsec;
|
||||||
|
if (diff.tv_nsec < 0) {
|
||||||
|
diff.tv_sec--;
|
||||||
|
diff.tv_nsec += 1000000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return (int) (diff.tv_sec * 1000 + (diff.tv_nsec + 500)/1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer_cb(struct UCTimers *timers, struct UCTimer *timer)
|
||||||
|
{
|
||||||
|
struct RTPSender *s = UC_CONTAINER_OF(timer, struct RTPSender, timer);
|
||||||
|
int rc;
|
||||||
|
ssize_t r;
|
||||||
|
struct timespec ts;
|
||||||
|
int diff;
|
||||||
|
int adjust;
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
rc = rtp_session_send_with_ts(s->rtp_sess,s->frame, sizeof s->frame, s->ts);
|
||||||
|
if(rc < sizeof s->frame) {
|
||||||
|
printf("Error, short send of %d bytes\n", rc);
|
||||||
|
}
|
||||||
|
s->ts += 160;
|
||||||
|
|
||||||
|
r = fread(s->frame,1, sizeof s->frame, s->file);
|
||||||
|
if (r <= 0) {
|
||||||
|
rtp_session_bye(s->rtp_sess, "Finished");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = diffts(&s->last_ts, &ts);
|
||||||
|
diff -= 20000;
|
||||||
|
|
||||||
|
s->accum_diff += diff;
|
||||||
|
|
||||||
|
if (s->accum_diff > 500)
|
||||||
|
adjust = -1000;
|
||||||
|
else if (s->accum_diff < -500)
|
||||||
|
adjust = 1000;
|
||||||
|
else
|
||||||
|
adjust = s->accum_diff;
|
||||||
|
|
||||||
|
if (s->accum_diff >= 20000 || s->accum_diff <= -20000) {
|
||||||
|
s->ts += 160;
|
||||||
|
printf("Skew ! accum_diff %d\n", s->accum_diff);
|
||||||
|
s->accum_diff -= 20000;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uc_timers_add(iomux_get_timers(mux), &s->timer, 0, 20 * 1000 + adjust);
|
||||||
|
|
||||||
|
s->last_ts = ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_sender(FILE* file, const char *remote_ip, uint16_t remote_port)
|
||||||
|
{
|
||||||
|
struct RTPSender *s = calloc(1, sizeof *s);
|
||||||
|
|
||||||
|
RtpSession *rtp_sess = rtp_session_new(RTP_SESSION_SENDONLY);
|
||||||
|
RtpProfile *rtp_prof = rtp_profile_new("pcmu8000");
|
||||||
|
rtp_profile_set_payload(rtp_prof, 0, &payload_type_pcmu8000);
|
||||||
|
rtp_session_set_profile(rtp_sess, rtp_prof);
|
||||||
|
//rtp_session_set_local_addr("192.168.1.55", 0);
|
||||||
|
rtp_session_set_remote_addr(rtp_sess, remote_ip, remote_port);
|
||||||
|
rtp_session_set_blocking_mode(rtp_sess, FALSE);
|
||||||
|
|
||||||
|
s->file = file;
|
||||||
|
strcpy(s->remote_ip, remote_ip);
|
||||||
|
s->remote_port = remote_port;
|
||||||
|
s->rtp_sess = rtp_sess;
|
||||||
|
s->rtp_profile = rtp_prof;
|
||||||
|
s->timer.callback = timer_cb;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &s->last_ts);
|
||||||
|
uc_timers_add(iomux_get_timers(mux), &s->timer, 0, 20000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
mux = iomux_create(IOMUX_TYPE_DEFAULT);
|
||||||
|
|
||||||
|
FILE *file;
|
||||||
|
if(argc != 4) {
|
||||||
|
puts("Specify a file name, remote IP and remote port");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strcmp(argv[1], "-") == 0) {
|
||||||
|
file = stdin;
|
||||||
|
} else {
|
||||||
|
file = fopen(argv[1], "rb");
|
||||||
|
if(file == NULL) {
|
||||||
|
perror("Cannot open file");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ortp_init();
|
||||||
|
ortp_set_log_level_mask(ORTP_DEBUG| ORTP_MESSAGE| ORTP_WARNING| ORTP_ERROR|ORTP_FATAL);
|
||||||
|
init_sender(file ,argv[2], atoi(argv[3]));
|
||||||
|
|
||||||
|
iomux_run(mux);
|
||||||
|
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
ortp_exit();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//compile:
|
||||||
|
// gcc -Wall -g -O `pkg-config --cflags --libs ortp` ortp-send-simple.c
|
||||||
@@ -25,7 +25,7 @@ START_TEST (test_container_of)
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Inner *innerp = &outer.inner;
|
struct Inner *innerp = &outer.inner;
|
||||||
struct Outer *outerp = CONTAINER_OF(innerp, struct Outer, inner);
|
struct Outer *outerp = UC_CONTAINER_OF(innerp, struct Outer, inner);
|
||||||
|
|
||||||
fail_if(outerp != &outer);
|
fail_if(outerp != &outer);
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -33,9 +33,7 @@ static suite_func suites[] = {
|
|||||||
read_file_suite,
|
read_file_suite,
|
||||||
pack_suite,
|
pack_suite,
|
||||||
logging_suite,
|
logging_suite,
|
||||||
threadqueue_suite,
|
|
||||||
buffer_suite,
|
buffer_suite,
|
||||||
clock_suite,
|
|
||||||
seq_suite,
|
seq_suite,
|
||||||
sat_math_suite,
|
sat_math_suite,
|
||||||
timers_suite,
|
timers_suite,
|
||||||
@@ -43,7 +41,9 @@ static suite_func suites[] = {
|
|||||||
human_bytesz_suite,
|
human_bytesz_suite,
|
||||||
dbuf_suite,
|
dbuf_suite,
|
||||||
sprintb_suite,
|
sprintb_suite,
|
||||||
strv_suite
|
strv_suite,
|
||||||
|
clock_suite,
|
||||||
|
threadqueue_suite
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <check.h>
|
#include <check.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <ucore/strvec.h>
|
#include <ucore/strvec.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -67,12 +68,61 @@ START_TEST (test_strv_null_terminate)
|
|||||||
|
|
||||||
rc = uc_strv_null_terminate(&strv);
|
rc = uc_strv_null_terminate(&strv);
|
||||||
fail_if(rc != 0);
|
fail_if(rc != 0);
|
||||||
|
fail_if(strv.cnt != 1); //shouldn't increase .cnt
|
||||||
fail_if(strv.strings[strv.cnt] != NULL);
|
fail_if(strv.strings[strv.cnt] != NULL);
|
||||||
|
|
||||||
uc_strv_destroy(&strv);
|
uc_strv_destroy(&strv);
|
||||||
|
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_strv_append_all_copy)
|
||||||
|
struct UCStrv src;
|
||||||
|
struct UCStrv dst;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
uc_strv_init(&src);
|
||||||
|
uc_strv_init(&dst);
|
||||||
|
|
||||||
|
uc_strv_append(&dst, "string1");
|
||||||
|
uc_strv_append(&src, "string2");
|
||||||
|
uc_strv_append(&src, "string3");
|
||||||
|
|
||||||
|
rc = uc_strv_append_all(&dst, &src, 1);
|
||||||
|
fail_if(rc != 0);
|
||||||
|
fail_if(dst.cnt != 3);
|
||||||
|
ck_assert_str_eq("string1", dst.strings[0]);
|
||||||
|
ck_assert_str_eq("string2", dst.strings[1]);
|
||||||
|
ck_assert_str_eq("string3", dst.strings[2]);
|
||||||
|
|
||||||
|
uc_strv_destroy(&src);
|
||||||
|
uc_strv_destroy(&dst);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_strv_append_all_nocopy)
|
||||||
|
struct UCStrv src;
|
||||||
|
struct UCStrv dst;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
uc_strv_init(&src);
|
||||||
|
uc_strv_init(&dst);
|
||||||
|
|
||||||
|
uc_strv_append(&dst, "string1");
|
||||||
|
uc_strv_append(&src, "string2");
|
||||||
|
uc_strv_append(&src, "string3");
|
||||||
|
|
||||||
|
rc = uc_strv_append_all(&dst, &src, 0);
|
||||||
|
fail_if(rc != 0);
|
||||||
|
fail_if(dst.cnt != 3);
|
||||||
|
ck_assert_str_eq("string1", dst.strings[0]);
|
||||||
|
ck_assert_str_eq("string2", dst.strings[1]);
|
||||||
|
ck_assert_str_eq("string3", dst.strings[2]);
|
||||||
|
|
||||||
|
uc_strv_destroy(&dst);
|
||||||
|
free(src.strings);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
Suite *strv_suite(void)
|
Suite *strv_suite(void)
|
||||||
{
|
{
|
||||||
@@ -83,6 +133,8 @@ Suite *strv_suite(void)
|
|||||||
tcase_add_test(tc, test_strv_clear);
|
tcase_add_test(tc, test_strv_clear);
|
||||||
tcase_add_test(tc, test_strv_nocopy);
|
tcase_add_test(tc, test_strv_nocopy);
|
||||||
tcase_add_test(tc, test_strv_null_terminate);
|
tcase_add_test(tc, test_strv_null_terminate);
|
||||||
|
tcase_add_test(tc, test_strv_append_all_copy);
|
||||||
|
tcase_add_test(tc, test_strv_append_all_nocopy);
|
||||||
|
|
||||||
suite_add_tcase(s, tc);
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
|||||||
+16
-22
@@ -164,37 +164,31 @@ START_TEST (test_timers_add_remove)
|
|||||||
struct UCoreSettableClock clk;
|
struct UCoreSettableClock clk;
|
||||||
struct TimerTest tt;
|
struct TimerTest tt;
|
||||||
struct UCTimers timers;
|
struct UCTimers timers;
|
||||||
struct UCTimer timer1;
|
struct UCTimer timer[1023];
|
||||||
struct UCTimer timer2;
|
|
||||||
struct UCTimer timer3;
|
|
||||||
struct UCTimer timer4;
|
|
||||||
struct timeval first;
|
struct timeval first;
|
||||||
|
size_t i;
|
||||||
|
int toggle = 5;
|
||||||
|
|
||||||
common_init(&clk, &tt, &timers, &timer1);
|
common_init(&clk, &tt, &timers, &timer[0]);
|
||||||
memset(&timer2, 0, sizeof timer2);
|
memset(&timer, 0, sizeof timer);
|
||||||
memset(&timer3, 0, sizeof timer2);
|
for (i = 0; i < sizeof timer/sizeof timer[0]; i++) {
|
||||||
memset(&timer4, 0, sizeof timer2);
|
timer[i].callback = timer_test_cb_add;
|
||||||
|
|
||||||
timer1.callback = timer_test_cb_add;
|
uc_timers_add(&timers, &timer[i], toggle + i , 0);
|
||||||
timer2.callback = timer_test_cb_add;
|
if (i > 5) //just to add timeouts non-ascending order
|
||||||
timer3.callback = timer_test_cb_add;
|
toggle = 5 - toggle;
|
||||||
timer4.callback = timer_test_cb_add;
|
}
|
||||||
|
|
||||||
uc_timers_add(&timers, &timer1, 10, 0);
|
|
||||||
uc_timers_add(&timers, &timer2, 5 , 0);
|
|
||||||
uc_timers_add(&timers, &timer3, 15, 1);
|
|
||||||
uc_timers_add(&timers, &timer4, 15, 1);
|
|
||||||
|
|
||||||
fail_if(uc_timers_first(&timers, &first) != 0);
|
fail_if(uc_timers_first(&timers, &first) != 0);
|
||||||
fail_if(first.tv_sec != TEST_TIMER_START + 5);
|
fail_if(first.tv_sec != TEST_TIMER_START + 5);
|
||||||
fail_if(first.tv_usec != 0);
|
fail_if(first.tv_usec != 0);
|
||||||
|
|
||||||
fail_if(uc_timers_count(&timers) != 4);
|
fail_if(uc_timers_count(&timers) != sizeof timer/sizeof timer[0]);
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof timer/sizeof timer[0]; i++) {
|
||||||
|
uc_timers_remove(&timers, &timer[i]);
|
||||||
|
}
|
||||||
|
|
||||||
uc_timers_remove(&timers, &timer1);
|
|
||||||
uc_timers_remove(&timers, &timer2);
|
|
||||||
uc_timers_remove(&timers, &timer3);
|
|
||||||
uc_timers_remove(&timers, &timer4);
|
|
||||||
|
|
||||||
fail_if(uc_timers_count(&timers) != 0);
|
fail_if(uc_timers_count(&timers) != 0);
|
||||||
fail_if(uc_timers_first(&timers, &first) == 0);
|
fail_if(uc_timers_first(&timers, &first) == 0);
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ void t2_cb(struct UCTimers *timers, struct UCTimer *timer)
|
|||||||
|
|
||||||
void mystruct1_cb(struct UCTimers *timers, struct UCTimer *timer)
|
void mystruct1_cb(struct UCTimers *timers, struct UCTimer *timer)
|
||||||
{
|
{
|
||||||
struct MyStruct *mystruct = CONTAINER_OF(timer, struct MyStruct, timer);
|
struct MyStruct *mystruct = UC_CONTAINER_OF(timer, struct MyStruct, timer);
|
||||||
|
|
||||||
TRACEF("MyStruct1 timer: %s\n", mystruct->str);
|
TRACEF("MyStruct1 timer: %s\n", mystruct->str);
|
||||||
uc_timers_add(timers, timer, 1, 0);
|
uc_timers_add(timers, timer, 1, 0);
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ void peer_do_state(struct HBPeer *peer, enum PeerEvent event);
|
|||||||
|
|
||||||
void peer_timer_cb(struct UCTimers *timers, struct UCTimer *timer)
|
void peer_timer_cb(struct UCTimers *timers, struct UCTimer *timer)
|
||||||
{
|
{
|
||||||
struct HBPeer *peer = CONTAINER_OF(timer, struct HBPeer, timer);
|
struct HBPeer *peer = UC_CONTAINER_OF(timer, struct HBPeer, timer);
|
||||||
struct HBContext *ctx = timer->cookie_ptr;
|
struct HBContext *ctx = timer->cookie_ptr;
|
||||||
time_t now;
|
time_t now;
|
||||||
|
|
||||||
@@ -181,7 +181,7 @@ void peer_received(struct HBPeer *peer)
|
|||||||
|
|
||||||
void hb_read(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event)
|
void hb_read(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event)
|
||||||
{
|
{
|
||||||
struct HBContext *ctx = CONTAINER_OF(fd, struct HBContext, sock_fd);
|
struct HBContext *ctx = UC_CONTAINER_OF(fd, struct HBContext, sock_fd);
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
struct sockaddr_in peer_addr;
|
struct sockaddr_in peer_addr;
|
||||||
socklen_t peer_len = sizeof peer_addr;
|
socklen_t peer_len = sizeof peer_addr;
|
||||||
|
|||||||
Reference in New Issue
Block a user