/*
 * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
 * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
 *
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
 *
 * The Initial Developer of the Original Code is
 * Anthony Minessale II <anthm@freeswitch.org>
 * Portions created by the Initial Developer are Copyright (C)
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Anthony Minessale II <anthm@freeswitch.org>
 * Eliot Gable <egable@gmail.com>
 *
 * switch_apr.h -- APR includes header
 *
 */
/*! \file switch_apr.h
    \brief APR includes header

	The things powered by APR are renamed into the switch_ namespace to provide a cleaner
	look to things and helps me to document what parts of APR I am using I'd like to take this
	opportunity to thank APR for all the awesome stuff it does and for making my life much easier.

*/
#ifndef SWITCH_APR_H
#define SWITCH_APR_H

SWITCH_BEGIN_EXTERN_C

SWITCH_DECLARE(int) switch_status_is_timeup(int status);

#ifdef WIN32
typedef DWORD switch_thread_id_t;
#else
#include <pthread.h>
typedef pthread_t switch_thread_id_t;
#endif

SWITCH_DECLARE(switch_thread_id_t) switch_thread_self(void);

/*! \brief Compare two thread ids
 *  \param tid1 1st Thread ID to compare
 *  \param tid2 2nd Thread ID to compare
*/
SWITCH_DECLARE(int) switch_thread_equal(switch_thread_id_t tid1, switch_thread_id_t tid2);


/*
   The pieces of apr we allow ppl to pass around between modules we typedef into our namespace and wrap all the functions
   any other apr code should be as hidden as possible.
*/
/**
 * @defgroup switch_apr Brought To You By APR
 * @ingroup FREESWITCH
 * @{
 */
/**
 * @defgroup switch_memory_pool Memory Pool Functions
 * @ingroup switch_apr
 * @{
 */
/** The fundamental pool type */
/* see switch types.h 	typedef struct fspr_pool_t switch_memory_pool_t;*/
/**
 * Clear all memory in the pool and run all the cleanups. This also destroys all
 * subpools.
 * @param pool The pool to clear
 * @remark This does not actually free the memory, it just allows the pool
 *         to re-use this memory for the next allocation.
 * @see fspr_pool_destroy()
 */
SWITCH_DECLARE(void) switch_pool_clear(switch_memory_pool_t *pool);

/** @} */

/**
 * @defgroup switch_string String Handling funcions
 * @ingroup switch_apr
 * @{
 */

SWITCH_DECLARE(int) switch_snprintf(_Out_z_cap_(len)
									char *buf, _In_ switch_size_t len, _In_z_ _Printf_format_string_ const char *format, ...);

SWITCH_DECLARE(int) switch_vasprintf(_Out_opt_ char **buf, _In_z_ _Printf_format_string_ const char *format, _In_ va_list ap);

SWITCH_DECLARE(int) switch_vsnprintf(char *buf, switch_size_t len, const char *format, va_list ap);

SWITCH_DECLARE(char *) switch_copy_string(_Out_z_cap_(dst_size)
										  char *dst, _In_z_ const char *src, _In_ switch_size_t dst_size);

/** @} */

#if 0
/**
 * @defgroup fspr_hash Hash Tables
 * @ingroup switch_apr
 * @{
 */

/** Abstract type for hash tables. */
	 typedef struct fspr_hash_t switch_hash_t;

/** Abstract type for scanning hash tables. */
	 typedef struct fspr_hash_index_t switch_hash_index_t;

/**
 * When passing a key to switch_hashfunc_default, this value can be
 * passed to indicate a string-valued key, and have the length compute automatically.
 *
 */
#define SWITCH_HASH_KEY_STRING     (-1)

/**
 * Start iterating over the entries in a hash table.
 * @param p The pool to allocate the switch_hash_index_t iterator. If this
 *          pool is NULL, then an internal, non-thread-safe iterator is used.
 * @param ht The hash table
 * @remark  There is no restriction on adding or deleting hash entries during
 * an iteration (although the results may be unpredictable unless all you do
 * is delete the current entry) and multiple iterations can be in
 * progress at the same time.

 */
SWITCH_DECLARE(switch_hash_index_t *) switch_core_hash_first(switch_memory_pool_t *pool, switch_hash_t *ht);

/**
 * Continue iterating over the entries in a hash table.
 * @param ht The iteration state
 * @return a pointer to the updated iteration state.  NULL if there are no more
 *         entries.
 */
SWITCH_DECLARE(switch_hash_index_t *) switch_core_hash_next(switch_hash_index_t *ht);

/**
 * Get the current entry's details from the iteration state.
 * @param hi The iteration state
 * @param key Return pointer for the pointer to the key.
 * @param klen Return pointer for the key length.
 * @param val Return pointer for the associated value.
 * @remark The return pointers should point to a variable that will be set to the
 *         corresponding data, or they may be NULL if the data isn't interesting.
 */
SWITCH_DECLARE(void) switch_core_hash_this(switch_hash_index_t *hi, const void **key, switch_ssize_t *klen, void **val);



SWITCH_DECLARE(switch_memory_pool_t *) switch_hash_pool_get(switch_hash_t *ht);

/** @} */


#endif

/**
 * The default hash function.
 * @param key pointer to the key.
 * @param klen the key length.
 *
 */
SWITCH_DECLARE(unsigned int) switch_hashfunc_default(const char *key, switch_ssize_t *klen);

SWITCH_DECLARE(unsigned int) switch_ci_hashfunc_default(const char *char_key, switch_ssize_t *klen);


 /**
 * @defgroup switch_time Time Routines
 * @ingroup switch_apr
 * @{
 */

 /** number of microseconds since 00:00:00 january 1, 1970 UTC */
	 typedef int64_t switch_time_t;

 /** number of microseconds in the interval */
	 typedef int64_t switch_interval_time_t;

/**
 * a structure similar to ANSI struct tm with the following differences:
 *  - tm_usec isn't an ANSI field
 *  - tm_gmtoff isn't an ANSI field (it's a bsdism)
 */
	 typedef struct switch_time_exp_t {
	/** microseconds past tm_sec */
		 int32_t tm_usec;
	/** (0-61) seconds past tm_min */
		 int32_t tm_sec;
	/** (0-59) minutes past tm_hour */
		 int32_t tm_min;
	/** (0-23) hours past midnight */
		 int32_t tm_hour;
	/** (1-31) day of the month */
		 int32_t tm_mday;
	/** (0-11) month of the year */
		 int32_t tm_mon;
	/** year since 1900 */
		 int32_t tm_year;
	/** (0-6) days since sunday */
		 int32_t tm_wday;
	/** (0-365) days since jan 1 */
		 int32_t tm_yday;
	/** daylight saving time */
		 int32_t tm_isdst;
	/** seconds east of UTC */
		 int32_t tm_gmtoff;
	 } switch_time_exp_t;

SWITCH_DECLARE(switch_time_t) switch_time_make(switch_time_t sec, int32_t usec);

/**
 * @return the current time
 */
SWITCH_DECLARE(switch_time_t) switch_time_now(void);

/**
 * Convert time value from human readable format to a numeric fspr_time_t that
 * always represents GMT
 * @param result the resulting imploded time
 * @param input the input exploded time
 */
SWITCH_DECLARE(switch_status_t) switch_time_exp_gmt_get(switch_time_t *result, switch_time_exp_t *input);

/**
 * formats the exploded time according to the format specified
 * @param s string to write to
 * @param retsize The length of the returned string
 * @param max The maximum length of the string
 * @param format The format for the time string
 * @param tm The time to convert
 */
SWITCH_DECLARE(switch_status_t) switch_strftime(char *s, switch_size_t *retsize, switch_size_t max, const char *format, switch_time_exp_t *tm);

/**
 * formats the exploded time according to the format specified (does not validate format string)
 * @param s string to write to
 * @param retsize The length of the returned string
 * @param max The maximum length of the string
 * @param format The format for the time string
 * @param tm The time to convert
 */
SWITCH_DECLARE(switch_status_t) switch_strftime_nocheck(char *s, switch_size_t *retsize, switch_size_t max, const char *format, switch_time_exp_t *tm);

/**
 * switch_rfc822_date formats dates in the RFC822
 * format in an efficient manner.  It is a fixed length
 * format which requires the indicated amount of storage,
 * including the trailing NUL terminator.
 * @param date_str String to write to.
 * @param t the time to convert
 */
SWITCH_DECLARE(switch_status_t) switch_rfc822_date(char *date_str, switch_time_t t);

/**
 * convert a time to its human readable components in GMT timezone
 * @param result the exploded time
 * @param input the time to explode
 */
SWITCH_DECLARE(switch_status_t) switch_time_exp_gmt(switch_time_exp_t *result, switch_time_t input);

/**
 * Convert time value from human readable format to a numeric fspr_time_t
 * e.g. elapsed usec since epoch
 * @param result the resulting imploded time
 * @param input the input exploded time
 */
SWITCH_DECLARE(switch_status_t) switch_time_exp_get(switch_time_t *result, switch_time_exp_t *input);

/**
 * convert a time to its human readable components in local timezone
 * @param result the exploded time
 * @param input the time to explode
 */
SWITCH_DECLARE(switch_status_t) switch_time_exp_lt(switch_time_exp_t *result, switch_time_t input);

/**
 * convert a time to its human readable components in a specific timezone with offset
 * @param result the exploded time
 * @param input the time to explode
 */
SWITCH_DECLARE(switch_status_t) switch_time_exp_tz(switch_time_exp_t *result, switch_time_t input, switch_int32_t offs);

/**
 * Sleep for the specified number of micro-seconds.
 * @param t desired amount of time to sleep.
 * @warning May sleep for longer than the specified time.
 */
SWITCH_DECLARE(void) switch_sleep(switch_interval_time_t t);
SWITCH_DECLARE(void) switch_micro_sleep(switch_interval_time_t t);

/** @} */

/**
 * @defgroup switch_thread_mutex Thread Mutex Routines
 * @ingroup switch_apr
 * @{
 */

/** Opaque thread-local mutex structure */
	 typedef struct fspr_thread_mutex_t switch_mutex_t;

/** Lock Flags */
#define SWITCH_MUTEX_DEFAULT	0x0	/**< platform-optimal lock behavior */
#define SWITCH_MUTEX_NESTED		0x1	/**< enable nested (recursive) locks */
#define	SWITCH_MUTEX_UNNESTED	0x2	/**< disable nested locks */

/**
 * Create and initialize a mutex that can be used to synchronize threads.
 * @param lock the memory address where the newly created mutex will be
 *        stored.
 * @param flags Or'ed value of:
 * <PRE>
 *           SWITCH_THREAD_MUTEX_DEFAULT   platform-optimal lock behavior.
 *           SWITCH_THREAD_MUTEX_NESTED    enable nested (recursive) locks.
 *           SWITCH_THREAD_MUTEX_UNNESTED  disable nested locks (non-recursive).
 * </PRE>
 * @param pool the pool from which to allocate the mutex.
 * @warning Be cautious in using SWITCH_THREAD_MUTEX_DEFAULT.  While this is the
 * most optimial mutex based on a given platform's performance charateristics,
 * it will behave as either a nested or an unnested lock.
 *
*/
SWITCH_DECLARE(switch_status_t) switch_mutex_init(switch_mutex_t ** lock, unsigned int flags, switch_memory_pool_t *pool);


/**
 * Destroy the mutex and free the memory associated with the lock.
 * @param lock the mutex to destroy.
 */
SWITCH_DECLARE(switch_status_t) switch_mutex_destroy(switch_mutex_t *lock);

/**
 * Acquire the lock for the given mutex. If the mutex is already locked,
 * the current thread will be put to sleep until the lock becomes available.
 * @param lock the mutex on which to acquire the lock.
 */
SWITCH_DECLARE(switch_status_t) switch_mutex_lock(switch_mutex_t *lock);

/**
 * Release the lock for the given mutex.
 * @param lock the mutex from which to release the lock.
 */
SWITCH_DECLARE(switch_status_t) switch_mutex_unlock(switch_mutex_t *lock);

/**
 * Attempt to acquire the lock for the given mutex. If the mutex has already
 * been acquired, the call returns immediately with APR_EBUSY. Note: it
 * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine
 * if the return value was APR_EBUSY, for portability reasons.
 * @param lock the mutex on which to attempt the lock acquiring.
 */
SWITCH_DECLARE(switch_status_t) switch_mutex_trylock(switch_mutex_t *lock);

/** @} */

/**
 * @defgroup switch_atomic Multi-Threaded Adtomic Operations Routines
 * @ingroup switch_apr
 * @{
 */

/** Opaque type used for the atomic operations */
#ifdef fspr_atomic_t
    typedef fspr_atomic_t switch_atomic_t;
#else
    typedef uint32_t switch_atomic_t;
#endif

/**
 * Some architectures require atomic operations internal structures to be
 * initialized before use.
 * @param pool The memory pool to use when initializing the structures.
 */
SWITCH_DECLARE(switch_status_t) switch_atomic_init(switch_memory_pool_t *pool);

/**
 * Uses an atomic operation to read the uint32 value at the location specified
 * by mem.
 * @param mem The location of memory which stores the value to read.
 */
SWITCH_DECLARE(uint32_t) switch_atomic_read(volatile switch_atomic_t *mem);

/**
 * Uses an atomic operation to set a uint32 value at a specified location of
 * memory.
 * @param mem The location of memory to set.
 * @param val The uint32 value to set at the memory location.
 */
SWITCH_DECLARE(void) switch_atomic_set(volatile switch_atomic_t *mem, uint32_t val);

/**
 * Uses an atomic operation to add the uint32 value to the value at the
 * specified location of memory.
 * @param mem The location of the value to add to.
 * @param val The uint32 value to add to the value at the memory location.
 */
SWITCH_DECLARE(void) switch_atomic_add(volatile switch_atomic_t *mem, uint32_t val);

/**
 * Uses an atomic operation to increment the value at the specified memroy
 * location.
 * @param mem The location of the value to increment.
 */
SWITCH_DECLARE(void) switch_atomic_inc(volatile switch_atomic_t *mem);

/**
 * Uses an atomic operation to decrement the value at the specified memroy
 * location.
 * @param mem The location of the value to decrement.
 */
SWITCH_DECLARE(int)  switch_atomic_dec(volatile switch_atomic_t *mem);

/** @} */

/**
 * @defgroup switch_thread_rwlock Thread Read/Write lock Routines
 * @ingroup switch_apr
 * @{
 */

/** Opaque structure used for the rwlock */
	 typedef struct fspr_thread_rwlock_t switch_thread_rwlock_t;

SWITCH_DECLARE(switch_status_t) switch_thread_rwlock_create(switch_thread_rwlock_t ** rwlock, switch_memory_pool_t *pool);
SWITCH_DECLARE(switch_status_t) switch_thread_rwlock_destroy(switch_thread_rwlock_t *rwlock);
SWITCH_DECLARE(switch_memory_pool_t *) switch_thread_rwlock_pool_get(switch_thread_rwlock_t *rwlock);
SWITCH_DECLARE(switch_status_t) switch_thread_rwlock_rdlock(switch_thread_rwlock_t *rwlock);
SWITCH_DECLARE(switch_status_t) switch_thread_rwlock_tryrdlock(switch_thread_rwlock_t *rwlock);
SWITCH_DECLARE(switch_status_t) switch_thread_rwlock_wrlock(switch_thread_rwlock_t *rwlock);
SWITCH_DECLARE(switch_status_t) switch_thread_rwlock_trywrlock(switch_thread_rwlock_t *rwlock);
SWITCH_DECLARE(switch_status_t) switch_thread_rwlock_trywrlock_timeout(switch_thread_rwlock_t *rwlock, int timeout);
SWITCH_DECLARE(switch_status_t) switch_thread_rwlock_unlock(switch_thread_rwlock_t *rwlock);

/** @} */

/**
 * @defgroup switch_thread_cond Condition Variable Routines
 * @ingroup switch_apr
 * @{
 */

/**
 * Note: destroying a condition variable (or likewise, destroying or
 * clearing the pool from which a condition variable was allocated) if
 * any threads are blocked waiting on it gives undefined results.
 */

/** Opaque structure for thread condition variables */
	 typedef struct fspr_thread_cond_t switch_thread_cond_t;

/**
 * Create and initialize a condition variable that can be used to signal
 * and schedule threads in a single process.
 * @param cond the memory address where the newly created condition variable
 *        will be stored.
 * @param pool the pool from which to allocate the mutex.
 */
SWITCH_DECLARE(switch_status_t) switch_thread_cond_create(switch_thread_cond_t ** cond, switch_memory_pool_t *pool);

/**
 * Put the active calling thread to sleep until signaled to wake up. Each
 * condition variable must be associated with a mutex, and that mutex must
 * be locked before  calling this function, or the behavior will be
 * undefined. As the calling thread is put to sleep, the given mutex
 * will be simultaneously released; and as this thread wakes up the lock
 * is again simultaneously acquired.
 * @param cond the condition variable on which to block.
 * @param mutex the mutex that must be locked upon entering this function,
 *        is released while the thread is asleep, and is again acquired before
 *        returning from this function.
 */
SWITCH_DECLARE(switch_status_t) switch_thread_cond_wait(switch_thread_cond_t *cond, switch_mutex_t *mutex);

/**
 * Put the active calling thread to sleep until signaled to wake up or
 * the timeout is reached. Each condition variable must be associated
 * with a mutex, and that mutex must be locked before calling this
 * function, or the behavior will be undefined. As the calling thread
 * is put to sleep, the given mutex will be simultaneously released;
 * and as this thread wakes up the lock is again simultaneously acquired.
 * @param cond the condition variable on which to block.
 * @param mutex the mutex that must be locked upon entering this function,
 *        is released while the thread is asleep, and is again acquired before
 *        returning from this function.
 * @param timeout The amount of time in microseconds to wait. This is
 *        a maximum, not a minimum. If the condition is signaled, we
 *        will wake up before this time, otherwise the error APR_TIMEUP
 *        is returned.
 */
SWITCH_DECLARE(switch_status_t) switch_thread_cond_timedwait(switch_thread_cond_t *cond, switch_mutex_t *mutex, switch_interval_time_t timeout);

/**
 * Signals a single thread, if one exists, that is blocking on the given
 * condition variable. That thread is then scheduled to wake up and acquire
 * the associated mutex. Although it is not required, if predictable scheduling
 * is desired, that mutex must be locked while calling this function.
 * @param cond the condition variable on which to produce the signal.
 */
SWITCH_DECLARE(switch_status_t) switch_thread_cond_signal(switch_thread_cond_t *cond);

/**
 * Signals all threads blocking on the given condition variable.
 * Each thread that was signaled is then scheduled to wake up and acquire
 * the associated mutex. This will happen in a serialized manner.
 * @param cond the condition variable on which to produce the broadcast.
 */
SWITCH_DECLARE(switch_status_t) switch_thread_cond_broadcast(switch_thread_cond_t *cond);

/**
 * Destroy the condition variable and free the associated memory.
 * @param cond the condition variable to destroy.
 */
SWITCH_DECLARE(switch_status_t) switch_thread_cond_destroy(switch_thread_cond_t *cond);

/** @} */

/**
 * @defgroup switch_UUID UUID Handling
 * @ingroup switch_apr
 * @{
 */

/** we represent a UUID as a block of 16 bytes. */

	 typedef struct {
		 unsigned char data[16];
							/**< the actual UUID */
	 } switch_uuid_t;

/** UUIDs are formatted as: 00112233-4455-6677-8899-AABBCCDDEEFF */
#define SWITCH_UUID_FORMATTED_LENGTH 256

#define SWITCH_MD5_DIGESTSIZE 16
#define SWITCH_MD5_DIGEST_STRING_SIZE 33

/**
 * Format a UUID into a string, following the standard format
 * @param buffer The buffer to place the formatted UUID string into. It must
 *               be at least APR_UUID_FORMATTED_LENGTH + 1 bytes long to hold
 *               the formatted UUID and a null terminator
 * @param uuid The UUID to format
 */
SWITCH_DECLARE(void) switch_uuid_format(char *buffer, const switch_uuid_t *uuid);

/**
 * Generate and return a (new) UUID
 * @param uuid The resulting UUID
 */
SWITCH_DECLARE(void) switch_uuid_get(switch_uuid_t *uuid);

/**
 * Parse a standard-format string into a UUID
 * @param uuid The resulting UUID
 * @param uuid_str The formatted UUID
 */
SWITCH_DECLARE(switch_status_t) switch_uuid_parse(switch_uuid_t *uuid, const char *uuid_str);

/**
 * MD5 in one step
 * @param digest The final MD5 digest
 * @param input The message block to use
 * @param inputLen The length of the message block
 */
SWITCH_DECLARE(switch_status_t) switch_md5(unsigned char digest[SWITCH_MD5_DIGESTSIZE], const void *input, switch_size_t inputLen);
SWITCH_DECLARE(switch_status_t) switch_md5_string(char digest_str[SWITCH_MD5_DIGEST_STRING_SIZE], const void *input, switch_size_t inputLen);

/** @} */

/**
 * @defgroup switch_FIFO Thread Safe FIFO bounded queue
 * @ingroup switch_apr
 * @{
 */

/** Opaque structure used for queue API */
	 typedef struct switch_apr_queue_t switch_queue_t;

/**
 * create a FIFO queue
 * @param queue The new queue
 * @param queue_capacity maximum size of the queue
 * @param pool a pool to allocate queue from
 */
SWITCH_DECLARE(switch_status_t) switch_queue_create(switch_queue_t ** queue, unsigned int queue_capacity, switch_memory_pool_t *pool);

/**
 * pop/get an object from the queue, blocking if the queue is already empty
 *
 * @param queue the queue
 * @param data the data
 * @returns APR_EINTR the blocking was interrupted (try again)
 * @returns APR_EOF if the queue has been terminated
 * @returns APR_SUCCESS on a successfull pop
 */
SWITCH_DECLARE(switch_status_t) switch_queue_pop(switch_queue_t *queue, void **data);

/**
 * pop/get an object from the queue, blocking if the queue is already empty
 *
 * @param queue the queue
 * @param data the data
 * @param timeout The amount of time in microseconds to wait. This is
 *        a maximum, not a minimum. If the condition is signaled, we
 *        will wake up before this time, otherwise the error APR_TIMEUP
 *        is returned.
 * @returns APR_TIMEUP the request timed out
 * @returns APR_EINTR the blocking was interrupted (try again)
 * @returns APR_EOF if the queue has been terminated
 * @returns APR_SUCCESS on a successfull pop
 */
SWITCH_DECLARE(switch_status_t) switch_queue_pop_timeout(switch_queue_t *queue, void **data, switch_interval_time_t timeout);

/**
 * push/add a object to the queue, blocking if the queue is already full
 *
 * @param queue the queue
 * @param data the data
 * @returns APR_EINTR the blocking was interrupted (try again)
 * @returns APR_EOF the queue has been terminated
 * @returns APR_SUCCESS on a successfull push
 */
SWITCH_DECLARE(switch_status_t) switch_queue_push(switch_queue_t *queue, void *data);

/**
 * returns the size of the queue.
 *
 * @warning this is not threadsafe, and is intended for reporting/monitoring
 * of the queue.
 * @param queue the queue
 * @returns the size of the queue
 */
SWITCH_DECLARE(unsigned int) switch_queue_size(switch_queue_t *queue);

/**
 * pop/get an object to the queue, returning immediatly if the queue is empty
 *
 * @param queue the queue
 * @param data the data
 * @returns APR_EINTR the blocking operation was interrupted (try again)
 * @returns APR_EAGAIN the queue is empty
 * @returns APR_EOF the queue has been terminated
 * @returns APR_SUCCESS on a successfull push
 */
SWITCH_DECLARE(switch_status_t) switch_queue_trypop(switch_queue_t *queue, void **data);

SWITCH_DECLARE(switch_status_t) switch_queue_interrupt_all(switch_queue_t *queue);

SWITCH_DECLARE(switch_status_t) switch_queue_term(switch_queue_t *queue);

/**
 * push/add a object to the queue, returning immediatly if the queue is full
 *
 * @param queue the queue
 * @param data the data
 * @returns APR_EINTR the blocking operation was interrupted (try again)
 * @returns APR_EAGAIN the queue is full
 * @returns APR_EOF the queue has been terminated
 * @returns APR_SUCCESS on a successfull push
 */
SWITCH_DECLARE(switch_status_t) switch_queue_trypush(switch_queue_t *queue, void *data);

/** @} */

/**
 * @defgroup switch_file_io File I/O Handling Functions
 * @ingroup switch_apr
 * @{
 */

/** Structure for referencing files. */
	 typedef struct fspr_file_t switch_file_t;

	 typedef int32_t switch_fileperms_t;
	 typedef int switch_seek_where_t;

	 /**
 * @defgroup fspr_file_seek_flags File Seek Flags
 * @{
 */

/* flags for fspr_file_seek */
/** Set the file position */
#define SWITCH_SEEK_SET SEEK_SET
/** Current */
#define SWITCH_SEEK_CUR SEEK_CUR
/** Go to end of file */
#define SWITCH_SEEK_END SEEK_END
/** @} */


/**
 * @defgroup switch_file_permissions File Permissions flags
 * @ingroup switch_file_io
 * @{
 */

#define SWITCH_FPROT_USETID 0x8000			/**< Set user id */
#define SWITCH_FPROT_UREAD 0x0400			/**< Read by user */
#define SWITCH_FPROT_UWRITE 0x0200			/**< Write by user */
#define SWITCH_FPROT_UEXECUTE 0x0100		/**< Execute by user */

#define SWITCH_FPROT_GSETID 0x4000			/**< Set group id */
#define SWITCH_FPROT_GREAD 0x0040			/**< Read by group */
#define SWITCH_FPROT_GWRITE 0x0020			/**< Write by group */
#define SWITCH_FPROT_GEXECUTE 0x0010		/**< Execute by group */

#define SWITCH_FPROT_WSTICKY 0x2000
#define SWITCH_FPROT_WREAD 0x0004			/**< Read by others */
#define SWITCH_FPROT_WWRITE 0x0002			/**< Write by others */
#define SWITCH_FPROT_WEXECUTE 0x0001		/**< Execute by others */

#define SWITCH_FPROT_OS_DEFAULT 0x0FFF		/**< use OS's default permissions */

/* additional permission flags for fspr_file_copy  and fspr_file_append */
#define SWITCH_FPROT_FILE_SOURCE_PERMS 0x1000	/**< Copy source file's permissions */
/** @} */

/* File lock types/flags */
/**
 * @defgroup switch_file_lock_types File Lock Types
 * @{
 */

#define SWITCH_FLOCK_SHARED        1	   /**< Shared lock. More than one process
                                           or thread can hold a shared lock
                                           at any given time. Essentially,
                                           this is a "read lock", preventing
                                           writers from establishing an
                                           exclusive lock. */
#define SWITCH_FLOCK_EXCLUSIVE     2	   /**< Exclusive lock. Only one process
                                           may hold an exclusive lock at any
                                           given time. This is analogous to
                                           a "write lock". */

#define SWITCH_FLOCK_TYPEMASK      0x000F  /**< mask to extract lock type */
#define SWITCH_FLOCK_NONBLOCK      0x0010  /**< do not block while acquiring the
                                           file lock */

 /** @} */

/**
 * @defgroup switch_file_open_flags File Open Flags/Routines
 * @ingroup switch_file_io
 * @{
 */
#define SWITCH_FOPEN_READ				0x00001		/**< Open the file for reading */
#define SWITCH_FOPEN_WRITE				0x00002		/**< Open the file for writing */
#define SWITCH_FOPEN_CREATE				0x00004		/**< Create the file if not there */
#define SWITCH_FOPEN_APPEND				0x00008		/**< Append to the end of the file */
#define SWITCH_FOPEN_TRUNCATE			0x00010		/**< Open the file and truncate to 0 length */
#define SWITCH_FOPEN_BINARY				0x00020		/**< Open the file in binary mode */
#define SWITCH_FOPEN_EXCL				0x00040		/**< Open should fail if APR_CREATE and file exists. */
#define SWITCH_FOPEN_BUFFERED			0x00080		/**< Open the file for buffered I/O */
#define SWITCH_FOPEN_DELONCLOSE			0x00100		/**< Delete the file after close */
#define SWITCH_FOPEN_XTHREAD			0x00200		/**< Platform dependent tag to open the file for use across multiple threads */
#define SWITCH_FOPEN_SHARELOCK			0x00400		/**< Platform dependent support for higher level locked read/write access to support writes across process/machines */
#define SWITCH_FOPEN_NOCLEANUP			0x00800		/**< Do not register a cleanup when the file is opened */
#define SWITCH_FOPEN_SENDFILE_ENABLED	0x01000		/**< Advisory flag that this file should support fspr_socket_sendfile operation */
#define SWITCH_FOPEN_LARGEFILE			0x04000		/**< Platform dependent flag to enable large file support */
/** @} */

/**
 * Open the specified file.
 * @param newf The opened file descriptor.
 * @param fname The full path to the file (using / on all systems)
 * @param flag Or'ed value of:
 * <PRE>
 *         SWITCH_FOPEN_READ				open for reading
 *         SWITCH_FOPEN_WRITE				open for writing
 *         SWITCH_FOPEN_CREATE				create the file if not there
 *         SWITCH_FOPEN_APPEND				file ptr is set to end prior to all writes
 *         SWITCH_FOPEN_TRUNCATE			set length to zero if file exists
 *         SWITCH_FOPEN_BINARY				not a text file (This flag is ignored on
 *											UNIX because it has no meaning)
 *         SWITCH_FOPEN_BUFFERED			buffer the data.  Default is non-buffered
 *         SWITCH_FOPEN_EXCL				return error if APR_CREATE and file exists
 *         SWITCH_FOPEN_DELONCLOSE			delete the file after closing.
 *         SWITCH_FOPEN_XTHREAD				Platform dependent tag to open the file
 *											for use across multiple threads
 *         SWITCH_FOPEN_SHARELOCK			Platform dependent support for higher
 *											level locked read/write access to support
 *											writes across process/machines
 *         SWITCH_FOPEN_NOCLEANUP			Do not register a cleanup with the pool
 *											passed in on the <EM>pool</EM> argument (see below).
 *											The fspr_os_file_t handle in fspr_file_t will not
 *											be closed when the pool is destroyed.
 *         SWITCH_FOPEN_SENDFILE_ENABLED	Open with appropriate platform semantics
 *											for sendfile operations.  Advisory only,
 *											fspr_socket_sendfile does not check this flag.
 * </PRE>
 * @param perm Access permissions for file.
 * @param pool The pool to use.
 * @remark If perm is SWITCH_FPROT_OS_DEFAULT and the file is being created,
 * appropriate default permissions will be used.
 */
SWITCH_DECLARE(switch_status_t) switch_file_open(switch_file_t ** newf, const char *fname, int32_t flag, switch_fileperms_t perm,
												 switch_memory_pool_t *pool);


SWITCH_DECLARE(switch_status_t) switch_file_seek(switch_file_t *thefile, switch_seek_where_t where, int64_t *offset);


SWITCH_DECLARE(switch_status_t) switch_file_copy(const char *from_path, const char *to_path, switch_fileperms_t perms, switch_memory_pool_t *pool);

/**
 * Close the specified file.
 * @param thefile The file descriptor to close.
 */
SWITCH_DECLARE(switch_status_t) switch_file_close(switch_file_t *thefile);

SWITCH_DECLARE(switch_status_t) switch_file_trunc(switch_file_t *thefile, int64_t offset);

SWITCH_DECLARE(switch_status_t) switch_file_lock(switch_file_t *thefile, int type);

/**
 * Delete the specified file.
 * @param path The full path to the file (using / on all systems)
 * @param pool The pool to use.
 * @remark If the file is open, it won't be removed until all
 * instances are closed.
 */
SWITCH_DECLARE(switch_status_t) switch_file_remove(const char *path, switch_memory_pool_t *pool);

SWITCH_DECLARE(switch_status_t) switch_file_rename(const char *from_path, const char *to_path, switch_memory_pool_t *pool);

/**
 * Read data from the specified file.
 * @param thefile The file descriptor to read from.
 * @param buf The buffer to store the data to.
 * @param nbytes On entry, the number of bytes to read; on exit, the number
 * of bytes read.
 *
 * @remark fspr_file_read will read up to the specified number of
 * bytes, but never more.  If there isn't enough data to fill that
 * number of bytes, all of the available data is read.  The third
 * argument is modified to reflect the number of bytes read.  If a
 * char was put back into the stream via ungetc, it will be the first
 * character returned.
 *
 * @remark It is not possible for both bytes to be read and an APR_EOF
 * or other error to be returned.  APR_EINTR is never returned.
 */
SWITCH_DECLARE(switch_status_t) switch_file_read(switch_file_t *thefile, void *buf, switch_size_t *nbytes);

/**
 * Write data to the specified file.
 * @param thefile The file descriptor to write to.
 * @param buf The buffer which contains the data.
 * @param nbytes On entry, the number of bytes to write; on exit, the number
 *               of bytes written.
 *
 * @remark fspr_file_write will write up to the specified number of
 * bytes, but never more.  If the OS cannot write that many bytes, it
 * will write as many as it can.  The third argument is modified to
 * reflect the * number of bytes written.
 *
 * @remark It is possible for both bytes to be written and an error to
 * be returned.  APR_EINTR is never returned.
 */
SWITCH_DECLARE(switch_status_t) switch_file_write(switch_file_t *thefile, const void *buf, switch_size_t *nbytes);
SWITCH_DECLARE(int) switch_file_printf(switch_file_t *thefile, const char *format, ...);

SWITCH_DECLARE(switch_status_t) switch_file_mktemp(switch_file_t ** thefile, char *templ, int32_t flags, switch_memory_pool_t *pool);

SWITCH_DECLARE(switch_size_t) switch_file_get_size(switch_file_t *thefile);

SWITCH_DECLARE(switch_status_t) switch_file_exists(const char *filename, switch_memory_pool_t *pool);

SWITCH_DECLARE(switch_status_t) switch_directory_exists(const char *dirname, switch_memory_pool_t *pool);

/**
* Create a new directory on the file system.
* @param path the path for the directory to be created. (use / on all systems)
* @param perm Permissions for the new direcoty.
* @param pool the pool to use.
*/
SWITCH_DECLARE(switch_status_t) switch_dir_make(const char *path, switch_fileperms_t perm, switch_memory_pool_t *pool);

/** Creates a new directory on the file system, but behaves like
* 'mkdir -p'. Creates intermediate directories as required. No error
* will be reported if PATH already exists.
* @param path the path for the directory to be created. (use / on all systems)
* @param perm Permissions for the new direcoty.
* @param pool the pool to use.
*/
SWITCH_DECLARE(switch_status_t) switch_dir_make_recursive(const char *path, switch_fileperms_t perm, switch_memory_pool_t *pool);

	 typedef struct switch_dir switch_dir_t;

	 struct switch_array_header_t {
	/** The pool the array is allocated out of */
		 switch_memory_pool_t *pool;
	/** The amount of memory allocated for each element of the array */
		 int elt_size;
	/** The number of active elements in the array */
		 int nelts;
	/** The number of elements allocated in the array */
		 int nalloc;
	/** The elements in the array */
		 char *elts;
	 };
	 typedef struct switch_array_header_t switch_array_header_t;

SWITCH_DECLARE(switch_status_t) switch_dir_open(switch_dir_t ** new_dir, const char *dirname, switch_memory_pool_t *pool);
SWITCH_DECLARE(switch_status_t) switch_dir_close(switch_dir_t *thedir);
SWITCH_DECLARE(const char *) switch_dir_next_file(switch_dir_t *thedir, char *buf, switch_size_t len);
SWITCH_DECLARE(uint32_t) switch_dir_count(switch_dir_t *thedir);

/** @} */

/**
 * @defgroup switch_thread_proc Threads and Process Functions
 * @ingroup switch_apr
 * @{
 */

/** Opaque Thread structure. */
	 typedef struct fspr_thread_t switch_thread_t;

/** Opaque Thread attributes structure. */
	 typedef struct fspr_threadattr_t switch_threadattr_t;

/**
 * The prototype for any APR thread worker functions.
 * typedef void *(SWITCH_THREAD_FUNC *switch_thread_start_t)(switch_thread_t*, void*);
 */
	 typedef void *(SWITCH_THREAD_FUNC * switch_thread_start_t) (switch_thread_t *, void *);

//APR_DECLARE(fspr_status_t) fspr_threadattr_stacksize_set(fspr_threadattr_t *attr, switch_size_t stacksize)
SWITCH_DECLARE(switch_status_t) switch_threadattr_stacksize_set(switch_threadattr_t *attr, switch_size_t stacksize);

SWITCH_DECLARE(switch_status_t) switch_threadattr_priority_set(switch_threadattr_t *attr, switch_thread_priority_t priority);


/**
 * Create and initialize a new threadattr variable
 * @param new_attr The newly created threadattr.
 * @param pool The pool to use
 */
SWITCH_DECLARE(switch_status_t) switch_threadattr_create(switch_threadattr_t ** new_attr, switch_memory_pool_t *pool);

/**
 * Set if newly created threads should be created in detached state.
 * @param attr The threadattr to affect
 * @param on Non-zero if detached threads should be created.
 */
SWITCH_DECLARE(switch_status_t) switch_threadattr_detach_set(switch_threadattr_t *attr, int32_t on);

/**
 * Create a new thread of execution
 * @param new_thread The newly created thread handle.
 * @param attr The threadattr to use to determine how to create the thread
 * @param func The function to start the new thread in
 * @param data Any data to be passed to the starting function
 * @param cont The pool to use
 */
SWITCH_DECLARE(switch_status_t) switch_thread_create(switch_thread_t ** new_thread, switch_threadattr_t *attr,
													 switch_thread_start_t func, void *data, switch_memory_pool_t *cont);

/** @} */

/**
 * @defgroup switch_network_io Network Routines
 * @ingroup switch_apr
 * @{
 */

#define SWITCH_SO_LINGER 1
#define SWITCH_SO_KEEPALIVE 2
#define SWITCH_SO_DEBUG 4
#define SWITCH_SO_NONBLOCK 8
#define SWITCH_SO_REUSEADDR 16
#define SWITCH_SO_SNDBUF 64
#define SWITCH_SO_RCVBUF 128
#define SWITCH_SO_DISCONNECTED 256
#define SWITCH_SO_TCP_NODELAY 512
#define SWITCH_SO_TCP_KEEPIDLE 520
#define SWITCH_SO_TCP_KEEPINTVL 530
#define SWITCH_SO_IPV6_V6ONLY 16384 /* Don't accept IPv4 connections on an IPv6 listening socket. */

 /**
 * @def SWITCH_INET
 * Not all platforms have these defined, so we'll define them here
 * The default values come from FreeBSD 4.1.1
 */
#define SWITCH_INET     AF_INET
#ifdef AF_INET6
#define SWITCH_INET6    AF_INET6
#else
#define SWITCH_INET6 0
#endif

/** @def SWITCH_UNSPEC
 * Let the system decide which address family to use
 */
#ifdef AF_UNSPEC
#define SWITCH_UNSPEC   AF_UNSPEC
#else
#define SWITCH_UNSPEC   0
#endif

/** A structure to represent sockets */
	 typedef struct fspr_socket_t switch_socket_t;

/** Freeswitch's socket address type, used to ensure protocol independence */
	 typedef struct fspr_sockaddr_t switch_sockaddr_t;

	 typedef enum {
		 SWITCH_SHUTDOWN_READ,	   /**< no longer allow read request */
		 SWITCH_SHUTDOWN_WRITE,	   /**< no longer allow write requests */
		 SWITCH_SHUTDOWN_READWRITE /**< no longer allow read or write requests */
	 } switch_shutdown_how_e;

/**
 * @defgroup IP_Proto IP Protocol Definitions for use when creating sockets
 * @{
 */
#define SWITCH_PROTO_TCP       6   /**< TCP  */
#define SWITCH_PROTO_UDP      17   /**< UDP  */
#define SWITCH_PROTO_SCTP    132   /**< SCTP */
/** @} */

/* function definitions */

/**
 * Create a socket.
 * @param new_sock The new socket that has been set up.
 * @param family The address family of the socket (e.g., SWITCH_INET).
 * @param type The type of the socket (e.g., SOCK_STREAM).
 * @param protocol The protocol of the socket (e.g., SWITCH_PROTO_TCP).
 * @param pool The pool to use
 */
SWITCH_DECLARE(switch_status_t) switch_socket_create(switch_socket_t ** new_sock, int family, int type, int protocol, switch_memory_pool_t *pool);

/**
 * Shutdown either reading, writing, or both sides of a socket.
 * @param sock The socket to close
 * @param how How to shutdown the socket.  One of:
 * <PRE>
 *            SWITCH_SHUTDOWN_READ         no longer allow read requests
 *            SWITCH_SHUTDOWN_WRITE        no longer allow write requests
 *            SWITCH_SHUTDOWN_READWRITE    no longer allow read or write requests
 * </PRE>
 * @see switch_shutdown_how_e
 * @remark This does not actually close the socket descriptor, it just
 *      controls which calls are still valid on the socket.
 */
SWITCH_DECLARE(switch_status_t) switch_socket_shutdown(switch_socket_t *sock, switch_shutdown_how_e how);

/**
 * Close a socket.
 * @param sock The socket to close
 */
SWITCH_DECLARE(switch_status_t) switch_socket_close(switch_socket_t *sock);

/**
 * Bind the socket to its associated port
 * @param sock The socket to bind
 * @param sa The socket address to bind to
 * @remark This may be where we will find out if there is any other process
 *      using the selected port.
 */
SWITCH_DECLARE(switch_status_t) switch_socket_bind(switch_socket_t *sock, switch_sockaddr_t *sa);

/**
 * Listen to a bound socket for connections.
 * @param sock The socket to listen on
 * @param backlog The number of outstanding connections allowed in the sockets
 *                listen queue.  If this value is less than zero, the listen
 *                queue size is set to zero.
 */
SWITCH_DECLARE(switch_status_t) switch_socket_listen(switch_socket_t *sock, int32_t backlog);

/**
 * Accept a new connection request
 * @param new_sock A copy of the socket that is connected to the socket that
 *                 made the connection request.  This is the socket which should
 *                 be used for all future communication.
 * @param sock The socket we are listening on.
 * @param pool The pool for the new socket.
 */
SWITCH_DECLARE(switch_status_t) switch_socket_accept(switch_socket_t ** new_sock, switch_socket_t *sock, switch_memory_pool_t *pool);

/**
 * Issue a connection request to a socket either on the same machine
 * or a different one.
 * @param sock The socket we wish to use for our side of the connection
 * @param sa The address of the machine we wish to connect to.
 */
SWITCH_DECLARE(switch_status_t) switch_socket_connect(switch_socket_t *sock, switch_sockaddr_t *sa);

/**
 * Get socket fd for the switch socket passed
 * @param sock The socket we wish to have fd
 */
SWITCH_DECLARE(int) switch_socket_fd_get(switch_socket_t *sock);

SWITCH_DECLARE(uint16_t) switch_sockaddr_get_port(switch_sockaddr_t *sa);
SWITCH_DECLARE(const char *) switch_get_addr(char *buf, switch_size_t len, switch_sockaddr_t *in);
SWITCH_DECLARE(switch_status_t) switch_getnameinfo(char **hostname, switch_sockaddr_t *sa, int32_t flags);
SWITCH_DECLARE(int32_t) switch_sockaddr_get_family(switch_sockaddr_t *sa);
SWITCH_DECLARE(switch_status_t) switch_sockaddr_ip_get(char **addr, switch_sockaddr_t *sa);
SWITCH_DECLARE(int) switch_sockaddr_equal(const switch_sockaddr_t *sa1, const switch_sockaddr_t *sa2);


/**
 * Create fspr_sockaddr_t from hostname, address family, and port.
 * @param sa The new fspr_sockaddr_t.
 * @param hostname The hostname or numeric address string to resolve/parse, or
 *               NULL to build an address that corresponds to 0.0.0.0 or ::
 * @param family The address family to use, or SWITCH_UNSPEC if the system should
 *               decide.
 * @param port The port number.
 * @param flags Special processing flags:
 * <PRE>
 *       APR_IPV4_ADDR_OK          first query for IPv4 addresses; only look
 *                                 for IPv6 addresses if the first query failed;
 *                                 only valid if family is APR_UNSPEC and hostname
 *                                 isn't NULL; mutually exclusive with
 *                                 APR_IPV6_ADDR_OK
 *       APR_IPV6_ADDR_OK          first query for IPv6 addresses; only look
 *                                 for IPv4 addresses if the first query failed;
 *                                 only valid if family is APR_UNSPEC and hostname
 *                                 isn't NULL and APR_HAVE_IPV6; mutually exclusive
 *                                 with APR_IPV4_ADDR_OK
 * </PRE>
 * @param pool The pool for the fspr_sockaddr_t and associated storage.
 */
SWITCH_DECLARE(switch_status_t) switch_sockaddr_info_get(switch_sockaddr_t ** sa, const char *hostname,
														 int32_t family, switch_port_t port, int32_t flags, switch_memory_pool_t *pool);

SWITCH_DECLARE(switch_status_t) switch_sockaddr_create(switch_sockaddr_t **sa, switch_memory_pool_t *pool);

SWITCH_DECLARE(switch_status_t) switch_sockaddr_new(switch_sockaddr_t ** sa, const char *ip, switch_port_t port, switch_memory_pool_t *pool);

/**
 * Send data over a network.
 * @param sock The socket to send the data over.
 * @param buf The buffer which contains the data to be sent.
 * @param len On entry, the number of bytes to send; on exit, the number
 *            of bytes sent.
 * @remark
 * <PRE>
 * This functions acts like a blocking write by default.  To change
 * this behavior, use fspr_socket_timeout_set() or the APR_SO_NONBLOCK
 * socket option.
 *
 * It is possible for both bytes to be sent and an error to be returned.
 *
 * APR_EINTR is never returned.
 * </PRE>
 */
SWITCH_DECLARE(switch_status_t) switch_socket_send(switch_socket_t *sock, const char *buf, switch_size_t *len);

/**
 * @param sock The socket to send from
 * @param where The fspr_sockaddr_t describing where to send the data
 * @param flags The flags to use
 * @param buf  The data to send
 * @param len  The length of the data to send
 */
SWITCH_DECLARE(switch_status_t) switch_socket_sendto(switch_socket_t *sock, switch_sockaddr_t *where, int32_t flags, const char *buf,
													 switch_size_t *len);

SWITCH_DECLARE(switch_status_t) switch_socket_send_nonblock(switch_socket_t *sock, const char *buf, switch_size_t *len);

/**
 * @param from The fspr_sockaddr_t to fill in the recipient info
 * @param sock The socket to use
 * @param flags The flags to use
 * @param buf  The buffer to use
 * @param len  The length of the available buffer
 *
 */
SWITCH_DECLARE(switch_status_t) switch_socket_recvfrom(switch_sockaddr_t *from, switch_socket_t *sock, int32_t flags, char *buf, size_t *len);

SWITCH_DECLARE(switch_status_t) switch_socket_atmark(switch_socket_t *sock, int *atmark);

/**
 * Read data from a network.
 * @param sock The socket to read the data from.
 * @param buf The buffer to store the data in.
 * @param len On entry, the number of bytes to receive; on exit, the number
 *            of bytes received.
 * @remark
 * <PRE>
 * This functions acts like a blocking read by default.  To change
 * this behavior, use fspr_socket_timeout_set() or the APR_SO_NONBLOCK
 * socket option.
 * The number of bytes actually received is stored in argument 3.
 *
 * It is possible for both bytes to be received and an APR_EOF or
 * other error to be returned.
 *
 * APR_EINTR is never returned.
 * </PRE>
 */
SWITCH_DECLARE(switch_status_t) switch_socket_recv(switch_socket_t *sock, char *buf, switch_size_t *len);

/**
 * Setup socket options for the specified socket
 * @param sock The socket to set up.
 * @param opt The option we would like to configure.  One of:
 * <PRE>
 *            APR_SO_DEBUG      --  turn on debugging information
 *            APR_SO_KEEPALIVE  --  keep connections active
 *            APR_SO_LINGER     --  lingers on close if data is present
 *            APR_SO_NONBLOCK   --  Turns blocking on/off for socket
 *                                  When this option is enabled, use
 *                                  the APR_STATUS_IS_EAGAIN() macro to
 *                                  see if a send or receive function
 *                                  could not transfer data without
 *                                  blocking.
 *            APR_SO_REUSEADDR  --  The rules used in validating addresses
 *                                  supplied to bind should allow reuse
 *                                  of local addresses.
 *            APR_SO_SNDBUF     --  Set the SendBufferSize
 *            APR_SO_RCVBUF     --  Set the ReceiveBufferSize
 * </PRE>
 * @param on Value for the option.
 */
SWITCH_DECLARE(switch_status_t) switch_socket_opt_set(switch_socket_t *sock, int32_t opt, int32_t on);

/**
 * Query socket timeout for the specified socket
 * @param sock The socket to query
 * @param t Socket timeout returned from the query.
 * <PRE>
 *   t > 0  -- read and write calls return APR_TIMEUP if specified time
 *             elapsess with no data read or written
 *   t == 0 -- read and write calls never block
 *   t < 0  -- read and write calls block
 * </PRE>
 */
SWITCH_DECLARE(switch_status_t) switch_socket_timeout_get(switch_socket_t *sock, switch_interval_time_t *t);

/**
 * Setup socket timeout for the specified socket
 * @param sock The socket to set up.
 * @param t Value for the timeout.
 * <PRE>
 *   t > 0  -- read and write calls return APR_TIMEUP if specified time
 *             elapsess with no data read or written
 *   t == 0 -- read and write calls never block
 *   t < 0  -- read and write calls block
 * </PRE>
 */
SWITCH_DECLARE(switch_status_t) switch_socket_timeout_set(switch_socket_t *sock, switch_interval_time_t t);

/**
 * Join a Multicast Group
 * @param sock The socket to join a multicast group
 * @param join The address of the multicast group to join
 * @param iface Address of the interface to use.  If NULL is passed, the
 *              default multicast interface will be used. (OS Dependent)
 * @param source Source Address to accept transmissions from (non-NULL
 *               implies Source-Specific Multicast)
 */
SWITCH_DECLARE(switch_status_t) switch_mcast_join(switch_socket_t *sock, switch_sockaddr_t *join, switch_sockaddr_t *iface, switch_sockaddr_t *source);

/**
 * Set the Multicast Time to Live (ttl) for a multicast transmission.
 * @param sock The socket to set the multicast ttl
 * @param ttl Time to live to Assign. 0-255, default=1
 * @remark If the TTL is 0, packets will only be seen by sockets on the local machine,
 *     and only when multicast loopback is enabled.
 */
SWITCH_DECLARE(switch_status_t) switch_mcast_hops(switch_socket_t *sock, uint8_t ttl);

SWITCH_DECLARE(switch_status_t) switch_mcast_loopback(switch_socket_t *sock, uint8_t opt);
SWITCH_DECLARE(switch_status_t) switch_mcast_interface(switch_socket_t *sock, switch_sockaddr_t *iface);

/** @} */

	 typedef enum {
		 SWITCH_NO_DESC,		   /**< nothing here */
		 SWITCH_POLL_SOCKET,	   /**< descriptor refers to a socket */
		 SWITCH_POLL_FILE,		   /**< descriptor refers to a file */
		 SWITCH_POLL_LASTDESC	   /**< descriptor is the last one in the list */
	 } switch_pollset_type_t;

	 typedef union {
		 switch_file_t *f;		   /**< file */
		 switch_socket_t *s;	   /**< socket */
	 } switch_descriptor_t;

	 struct switch_pollfd {
		 switch_memory_pool_t *p;		  /**< associated pool */
		 switch_pollset_type_t desc_type;
									   /**< descriptor type */
		 int16_t reqevents;	/**< requested events */
		 int16_t rtnevents;	/**< returned events */
		 switch_descriptor_t desc;	 /**< @see fspr_descriptor */
		 void *client_data;		/**< allows app to associate context */
	 };



/**
 * @defgroup fspr_poll Poll Routines
 * @ingroup switch_apr
 * @{
 */
/** Poll descriptor set. */
	 typedef struct switch_pollfd switch_pollfd_t;

/** Opaque structure used for pollset API */
	 typedef struct fspr_pollset_t switch_pollset_t;

/**
 * Poll options
 */
#define SWITCH_POLLIN 0x001			/**< Can read without blocking */
#define SWITCH_POLLPRI 0x002			/**< Priority data available */
#define SWITCH_POLLOUT 0x004			/**< Can write without blocking */
#define SWITCH_POLLERR 0x010			/**< Pending error */
#define SWITCH_POLLHUP 0x020			/**< Hangup occurred */
#define SWITCH_POLLNVAL 0x040		/**< Descriptior invalid */

/**
 * Setup a pollset object
 * @param pollset  The pointer in which to return the newly created object
 * @param size The maximum number of descriptors that this pollset can hold
 * @param pool The pool from which to allocate the pollset
 * @param flags Optional flags to modify the operation of the pollset.
 *
 * @remark If flags equals APR_POLLSET_THREADSAFE, then a pollset is
 * created on which it is safe to make concurrent calls to
 * fspr_pollset_add(), fspr_pollset_remove() and fspr_pollset_poll() from
 * separate threads.  This feature is only supported on some
 * platforms; the fspr_pollset_create() call will fail with
 * APR_ENOTIMPL on platforms where it is not supported.
 */
SWITCH_DECLARE(switch_status_t) switch_pollset_create(switch_pollset_t ** pollset, uint32_t size, switch_memory_pool_t *pool, uint32_t flags);

/**
 * Add a socket or file descriptor to a pollset
 * @param pollset The pollset to which to add the descriptor
 * @param descriptor The descriptor to add
 * @remark If you set client_data in the descriptor, that value
 *         will be returned in the client_data field whenever this
 *         descriptor is signalled in fspr_pollset_poll().
 * @remark If the pollset has been created with APR_POLLSET_THREADSAFE
 *         and thread T1 is blocked in a call to fspr_pollset_poll() for
 *         this same pollset that is being modified via fspr_pollset_add()
 *         in thread T2, the currently executing fspr_pollset_poll() call in
 *         T1 will either: (1) automatically include the newly added descriptor
 *         in the set of descriptors it is watching or (2) return immediately
 *         with APR_EINTR.  Option (1) is recommended, but option (2) is
 *         allowed for implementations where option (1) is impossible
 *         or impractical.
 */
SWITCH_DECLARE(switch_status_t) switch_pollset_add(switch_pollset_t *pollset, const switch_pollfd_t *descriptor);

/**
 * Remove a descriptor from a pollset
 * @param pollset The pollset from which to remove the descriptor
 * @param descriptor The descriptor to remove
 * @remark If the pollset has been created with APR_POLLSET_THREADSAFE
 *         and thread T1 is blocked in a call to fspr_pollset_poll() for
 *         this same pollset that is being modified via fspr_pollset_remove()
 *         in thread T2, the currently executing fspr_pollset_poll() call in
 *         T1 will either: (1) automatically exclude the newly added descriptor
 *         in the set of descriptors it is watching or (2) return immediately
 *         with APR_EINTR.  Option (1) is recommended, but option (2) is
 *         allowed for implementations where option (1) is impossible
 *         or impractical.
 */
SWITCH_DECLARE(switch_status_t) switch_pollset_remove(switch_pollset_t *pollset, const switch_pollfd_t *descriptor);

/**
 * Poll the sockets in the poll structure
 * @param aprset The poll structure we will be using.
 * @param numsock The number of sockets we are polling
 * @param nsds The number of sockets signalled.
 * @param timeout The amount of time in microseconds to wait.  This is
 *                a maximum, not a minimum.  If a socket is signalled, we
 *                will wake up before this time.  A negative number means
 *                wait until a socket is signalled.
 * @remark The number of sockets signalled is returned in the third argument.
 *         This is a blocking call, and it will not return until either a
 *         socket has been signalled, or the timeout has expired.
 */
SWITCH_DECLARE(switch_status_t) switch_poll(switch_pollfd_t *aprset, int32_t numsock, int32_t *nsds, switch_interval_time_t timeout);

/**
 * Block for activity on the descriptor(s) in a pollset
 * @param pollset The pollset to use
 * @param timeout Timeout in microseconds
 * @param num Number of signalled descriptors (output parameter)
 * @param descriptors Array of signalled descriptors (output parameter)
 */
SWITCH_DECLARE(switch_status_t) switch_pollset_poll(switch_pollset_t *pollset, switch_interval_time_t timeout, int32_t *num, const switch_pollfd_t **descriptors);

/*!
  \brief Create a set of file descriptors to poll from a socket
  \param poll the polfd to create
  \param sock the socket to add
  \param flags the flags to modify the behaviour
  \param pool the memory pool to use
  \return SWITCH_STATUS_SUCCESS when successful
*/
SWITCH_DECLARE(switch_status_t) switch_socket_create_pollset(switch_pollfd_t ** poll, switch_socket_t *sock, int16_t flags, switch_memory_pool_t *pool);

SWITCH_DECLARE(switch_interval_time_t) switch_interval_time_from_timeval(struct timeval *tvp);


/*!
  \brief Create a pollfd out of a socket
  \param pollfd the pollfd to create
  \param sock the socket to add
  \param flags the flags to modify the behaviour
  \param client_data custom user data
  \param pool the memory pool to use
  \return SWITCH_STATUS_SUCCESS when successful
*/
SWITCH_DECLARE(switch_status_t) switch_socket_create_pollfd(switch_pollfd_t **pollfd, switch_socket_t *sock, int16_t flags, void *client_data, switch_memory_pool_t *pool);
SWITCH_DECLARE(switch_status_t) switch_match_glob(const char *pattern, switch_array_header_t ** result, switch_memory_pool_t *pool);
SWITCH_DECLARE(switch_status_t) switch_os_sock_get(switch_os_socket_t *thesock, switch_socket_t *sock);
SWITCH_DECLARE(switch_status_t) switch_os_sock_put(switch_socket_t **sock, switch_os_socket_t *thesock, switch_memory_pool_t *pool);
SWITCH_DECLARE(switch_status_t) switch_socket_addr_get(switch_sockaddr_t ** sa, switch_bool_t remote, switch_socket_t *sock);
/**
 * Create an anonymous pipe.
 * @param in The file descriptor to use as input to the pipe.
 * @param out The file descriptor to use as output from the pipe.
 * @param pool The pool to operate on.
 */
SWITCH_DECLARE(switch_status_t) switch_file_pipe_create(switch_file_t ** in, switch_file_t ** out, switch_memory_pool_t *pool);

/**
 * Get the timeout value for a pipe or manipulate the blocking state.
 * @param thepipe The pipe we are getting a timeout for.
 * @param timeout The current timeout value in microseconds.
 */
SWITCH_DECLARE(switch_status_t) switch_file_pipe_timeout_get(switch_file_t *thepipe, switch_interval_time_t *timeout);

/**
 * Set the timeout value for a pipe or manipulate the blocking state.
 * @param thepipe The pipe we are setting a timeout on.
 * @param timeout The timeout value in microseconds.  Values < 0 mean wait
 *        forever, 0 means do not wait at all.
 */
SWITCH_DECLARE(switch_status_t) switch_file_pipe_timeout_set(switch_file_t *thepipe, switch_interval_time_t timeout);


/**
 * stop the current thread
 * @param thd The thread to stop
 * @param retval The return value to pass back to any thread that cares
 */
SWITCH_DECLARE(switch_status_t) switch_thread_exit(switch_thread_t *thd, switch_status_t retval);

/**
 * block until the desired thread stops executing.
 * @param retval The return value from the dead thread.
 * @param thd The thread to join
 */
SWITCH_DECLARE(switch_status_t) switch_thread_join(switch_status_t *retval, switch_thread_t *thd);

/**
 * Return a human readable string describing the specified error.
 * @param statcode The error code the get a string for.
 * @param buf A buffer to hold the error string.
 * @bufsize Size of the buffer to hold the string.
 */

SWITCH_DECLARE(char *) switch_strerror(switch_status_t statcode, char *buf, switch_size_t bufsize);



/** @} */

SWITCH_END_EXTERN_C
#endif
/* For Emacs:
 * Local Variables:
 * mode:c
 * indent-tabs-mode:t
 * tab-width:4
 * c-basic-offset:4
 * End:
 * For VIM:
 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
 */
