Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 24 additions & 17 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,43 @@
#

CC = gcc
CFLAGS = -Wall -Werror -Wno-unused-parameter -Wextra -Wstrict-prototypes -Wmissing-prototypes -Wdeclaration-after-statement -Wmissing-declarations -Wmissing-format-attribute -Wformat=2 -Wshadow -std=gnu99 -pthread -O3 -g -Wstack-protector -fno-omit-frame-pointer -D_FORTIFY_SOURCE=2
CFLAGS = -Wall -Werror -Wno-unused-parameter -Wextra -Wstrict-prototypes -Wmissing-prototypes -Wdeclaration-after-statement -Wmissing-declarations -Wmissing-format-attribute -Wformat=2 -Wshadow -std=gnu99 -pthread -O0 -g -Wstack-protector -fno-omit-frame-pointer -D_FORTIFY_SOURCE=2 -I.
EXE = cami
SAMPEXES = simpleami amicli
LIBNAME = libcami
LIBS = -lm
LIBNAME = lib$(EXE).so
LIBS = -lm -ldl
RM = rm -f
INSTALL = install
INSTALL = install

all : library
all : library examples

%.o: %.c
$(CC) $(CFLAGS) -fPIC -c $^

library: $(EXE).o
$(LIBNAME): $(EXE).o
@echo "== Linking $@"
$(CC) -shared -fPIC -o $(LIBNAME).so $^ $(LIBS)
$(CC) -shared -fPIC -o $(LIBNAME) $^ $(LIBS)

library: $(LIBNAME)
@if [ ! -d /usr/include/$(EXE) ]; then \
ln -f -s include $(EXE); \
fi

install:
$(INSTALL) -m 755 $(LIBNAME).so "/usr/lib"
$(INSTALL) -m 755 $(LIBNAME) "/usr/lib"
mkdir -p /usr/include/$(EXE)
$(INSTALL) -m 755 include/*.h "/usr/include/$(EXE)/"
$(INSTALL) -m 644 include/*.h "/usr/include/$(EXE)/"

simpleami: library install simpleami.o
$(CC) $(CFLAGS) -o simpleami simpleami.o -l$(EXE) $(LIBS) -ldl
simpleami: simpleami.o $(LIBNAME)
$(CC) $(CFLAGS) -o $@ $@.o -L. -Wl,-rpath,. -l$(EXE) $(LIBS)

amicli: library install amicli.o
$(CC) $(CFLAGS) -o amicli amicli.o -l$(EXE) $(LIBS) -ldl
amicli: amicli.o $(LIBNAME)
$(CC) $(CFLAGS) -o $@ $@.o -L. -Wl,-rpath,. -l$(EXE) $(LIBS)

examples : $(SAMPEXES)
examples: $(SAMPEXES)

clean :
$(RM) *.i *.o $(EXE) $(SAMPEXES) $(LIBNAME).so
clean:
$(RM) *.i *.o $(EXE) $(SAMPEXES) $(LIBNAME)

uninstall:
$(RM) /usr/lib/$(EXE).so
Expand All @@ -48,5 +53,7 @@ uninstall:
.PHONY: all
.PHONY: library
.PHONY: install
.PHONY: example
.PHONY: examples
.PHONY: clean

# vim: set noexpandtab shiftwidth=4 tabstop=4:
2 changes: 1 addition & 1 deletion amicli.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ int main(int argc,char *argv[])
int debug = 0;
struct ami_session *ami;

while ((c = getopt(argc, argv, getopt_settings)) != -1) {
while ((c = getopt(argc, argv, getopt_settings)) != (char) -1) {
switch (c) {
case '?':
case 'd':
Expand Down
123 changes: 100 additions & 23 deletions cami.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
if (ami->debug_level >= level) { \
struct timeval tv; \
gettimeofday(&tv, NULL); \
if (ami->debugfd != -1) dprintf(ami->debugfd, "%llu:%03lu : %d : " fmt, (((long long)tv.tv_sec)), (tv.tv_usec/1000), __LINE__, ## __VA_ARGS__); \
if (ami->debugfd != -1) dprintf(ami->debugfd, "%llu:%03lu : %d : " fmt, (((unsigned long long)tv.tv_sec)), (unsigned long)(tv.tv_usec/1000), __LINE__, ## __VA_ARGS__); \
} \
}

Expand Down Expand Up @@ -101,14 +101,19 @@ struct ami_session {
unsigned int return_null_on_error:1;
};

/* Used for debugging prior to session creation */
static int ami_initial_debugfd = -1;
static int ami_initial_debug_level = 0;

static struct ami_session *ami_session_new(void)
{
struct ami_session *ami = calloc(1, sizeof(*ami));
if (!ami) {
return NULL;
}
ami->ami_socket = -1;
ami->debugfd = -1;
ami->debugfd = ami_initial_debugfd;
ami->debug_level = ami_initial_debug_level;
ami->ami_pipe[0] = ami->ami_pipe[1] = -1;
ami->ami_read_pipe[0] = ami->ami_read_pipe[1] = -1;
ami->ami_event_pipe[0] = ami->ami_event_pipe[1] = -1;
Expand Down Expand Up @@ -358,6 +363,7 @@ struct ami_session *ami_connect(const char *hostname, int port, void (*callback)
int fd;
struct sockaddr_in saddr;
struct ami_session *ami;
int ret;

ami = ami_session_new();
if (!ami) {
Expand Down Expand Up @@ -416,13 +422,57 @@ struct ami_session *ami_connect(const char *hostname, int port, void (*callback)
goto cleanup;
}
ami->ami_socket = fd;
inet_pton(AF_INET, hostname, &(saddr.sin_addr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port); /* use network order */
if (connect(fd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
ami_error(ami, "connect failed: %s\n", strerror(errno));
ami_cleanup(ami);
goto cleanup;
if (inet_pton(AF_INET, hostname, &(saddr.sin_addr)) == 1) {
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port); /* use network order */
if (connect(fd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
ami_error(ami, "connect failed: %s\n", strerror(errno));
ami_cleanup(ami);
goto cleanup;
}
} else {
struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM,
.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG
};
struct addrinfo *res;

if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
if (res->ai_addr == NULL) {
freeaddrinfo(res);
ami_error(ami, "host %s not valid\n", hostname);
ami_cleanup(ami);
goto cleanup;
}

switch (res->ai_addr->sa_family) {
case AF_INET:
((struct sockaddr_in *)res->ai_addr)->sin_port = htons(port);
break;
case AF_INET6:
((struct sockaddr_in6 *)res->ai_addr)->sin6_port = htons(port);
break;
default:
freeaddrinfo(res);
ami_error(ami, "address for host %s not valid\n", hostname);
ami_cleanup(ami);
goto cleanup;
}

if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) {
freeaddrinfo(res);
ami_error(ami, "connect failed: %s\n", strerror(errno));
ami_cleanup(ami);
goto cleanup;
}

freeaddrinfo(res);
} else {
ami_error(ami, "host %s not valid\n", hostname);
ami_cleanup(ami);
goto cleanup;
}
}
ami->ami_callback = callback;
ami->disconnected_callback = dis_callback;
Expand All @@ -438,18 +488,37 @@ struct ami_session *ami_connect(const char *hostname, int port, void (*callback)
pthread_mutexattr_destroy(&attr);
}

if (pthread_create(&ami->ami_thread, NULL, ami_loop, ami)) {
ami_error(ami, "Unable to create AMI thread: %s\n", strerror(errno));
ami_cleanup(ami);
goto cleanup;
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 2 * 1024 * 1024);
ret = pthread_create(&ami->ami_thread, &attr, ami_loop, ami);
pthread_attr_destroy(&attr);
if (ret) {
ami_error(ami, "Unable to create AMI thread: %s\n", strerror(errno));
ami_cleanup(ami);
goto cleanup;
}
}
if (pthread_create(&ami->dispatch_thread, NULL, ami_event_dispatch, ami)) {
ami_error(ami, "Unable to create dispatch thread: %s\n", strerror(errno));
ami_cleanup(ami);
goto cleanup;

{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 2 * 1024 * 1024);
ret = pthread_create(&ami->dispatch_thread, &attr, ami_event_dispatch, ami);
pthread_attr_destroy(&attr);
if (ret) {
ami_error(ami, "Unable to create dispatch thread: %s\n", strerror(errno));
ami_cleanup(ami);
goto cleanup;
}
}

pthread_mutex_unlock(&ami->ami_read_lock);

/* establish the initial per-session debug fd and level */
ami->debugfd = -1;
ami->debug_level = 0;
return ami;

cleanup:
Expand Down Expand Up @@ -506,20 +575,28 @@ void ami_destroy(struct ami_session *ami)

void ami_set_debug(struct ami_session *ami, int fd)
{
ami->debugfd = fd;
if (ami) {
ami->debugfd = fd;
} else {
ami_initial_debugfd = fd;
}
}

int ami_set_debug_level(struct ami_session *ami, int level)
{
int old_level = ami->debug_level;
int old_level = ami ? ami->debug_level : ami_initial_debug_level;
if (level < 0 || level > 10) {
return -1;
}
ami->debug_level = level;
if (ami) {
ami->debug_level = level;
} else {
ami_initial_debug_level = level;
}
return old_level;
}

static int __attribute__ ((format (gnu_printf, 4, 5))) __ami_send(struct ami_session *ami, va_list ap, const char *fmt, const char *prefmt, ...)
static int __attribute__ ((format (printf, 3, 0))) __attribute__ ((format (printf, 4, 5))) __ami_send(struct ami_session *ami, va_list ap, const char *fmt, const char *prefmt, ...)
{
int res = 0;
int bytes = 0;
Expand Down Expand Up @@ -1040,7 +1117,7 @@ static int ami_wait_for_response(struct ami_session *ami, int msgid)
}
}

static int ami_send(struct ami_session *ami, const char *action, const char *fmt, ...)
static int __attribute__ ((format (printf, 3, 4))) ami_send(struct ami_session *ami, const char *action, const char *fmt, ...)
{
int res;

Expand All @@ -1053,7 +1130,7 @@ static int ami_send(struct ami_session *ami, const char *action, const char *fmt
return res;
}

struct ami_response *ami_action(struct ami_session *ami, const char *action, const char *fmt, ...)
struct ami_response * __attribute__ ((format (printf, 3, 4))) ami_action(struct ami_session *ami, const char *action, const char *fmt, ...)
{
struct ami_response *resp = NULL;
/* Remember: no trailing \r\n in fmt !*/
Expand Down
3 changes: 2 additions & 1 deletion include/cami.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ struct ami_response {

/*!
* \brief Enable debug logging
* \param ami
* \param ami The AMI session. If NULL, sets the file descriptor for debug logging prior to session creation (e.g. in ami_connect)
* \param fd File descriptor to which optional debug log messages should be delivered. Default is off (-1)
* \note This is not recommended for use in production, but may be helpful in a dev environment.
*/
Expand All @@ -59,6 +59,7 @@ void ami_set_debug(struct ami_session *ami, int fd);
/*!
* \brief Set debug logging level
* \param ami
* \param ami The AMI session. If NULL, sets the debug level prior to session creation (e.g. in ami_connect)
* \param level Level between 0 and 10. 0 will disable logging, 10 is the most granular. Default is 0.
* \note A log level of 1 is recommended for production use: this will log all errors and warnings. Use a greater log level for debugging.
* \retval -1 on failure, non-negative old log level otherwise
Expand Down
9 changes: 7 additions & 2 deletions simpleami.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
static void simple_callback(struct ami_session *ami, struct ami_event *event)
{
const char *eventname = ami_keyvalue(event, "Event");
(void) ami;

printf("(Callback) Event Received: %s\n", eventname);
#if 0
/* Or, you could print out the entire event contents for debugging, or to see what's there: */
Expand All @@ -57,8 +59,8 @@ static int simple_ami(const char *hostname, const char *username, const char *pa
struct ami_session *ami;
struct ami_response *resp = NULL;
#if 0
ami_set_debug(STDERR_FILENO); /* Not recommended for daemon programs */
ami_set_debug_level(1);
ami_set_debug(NULL, STDERR_FILENO); /* Not recommended for daemon programs */
ami_set_debug_level(NULL, 1);
#endif
ami = ami_connect(hostname, 0, simple_callback, simple_disconnect_callback);
if (!ami) {
Expand Down Expand Up @@ -95,6 +97,9 @@ static int simple_ami(const char *hostname, const char *username, const char *pa

int main(int argc,char *argv[])
{
(void) argc;
(void) argv;

if (simple_ami("127.0.0.1", "test", "test")) {
exit(EXIT_FAILURE);
}
Expand Down
Loading