Skip to content

Commit

Permalink
Fixes #1: keep a non-global state
Browse files Browse the repository at this point in the history
API restructured to take a pointer to a state struct (libifc_handle_t*).
Calling application obtains this pointer by calling libifc_open(), and frees/clears it by calling libifc_close(ptr).
Calling application may use as many libifc_handle_t* as it wishes. Intended use case is one per thread in a multithreaded application.
Calling application now use libifc_err_errtype(ptr), libifc_err_errno(ptr) and libifc_err_ioctlreq(ptr) to retrieve error information.
Exposed some internal APIs via libifconfig_internal.h. Currently intended for use by source files in libifconfig only, therefore not installed to the usual places.
  • Loading branch information
Savagedlight committed Apr 14, 2016
1 parent b565728 commit 6855998
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 157 deletions.
4 changes: 2 additions & 2 deletions Makefile.base
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
LIB= ifconfig
SHLIBDIR?= /lib
SHLIB_MAJOR= 1
SRCS= libifconfig.c libifconfig_socketcache.c
SRCS= libifconfig.c libifconfig_internal.c

INCSDIR= ${INCLUDEDIR}/libifconfig
INCS= libifconfig.h libifconfig_socketcache.h
INCS= libifconfig.h

#MAN= libifconfig.3

Expand Down
2 changes: 1 addition & 1 deletion Makefile.standalone
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
default:
$(CC) -Wall -fPIC -shared -o libifconfig.so libifconfig.c libifconfig_socketcache.c
$(CC) -Wall -fPIC -shared -o libifconfig.so libifconfig.c libifconfig_internal.c
140 changes: 77 additions & 63 deletions libifconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,59 +64,62 @@
#include <err.h>
#include <errno.h>
#include <fcntl.h>
//#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "libifconfig.h"
#include "libifconfig_socketcache.h"
#include "libifconfig_internal.h"

struct errstate libifc_errstate;

void libifc_free_resources(void) {
libifc_socketcache_free_resources();
libifc_handle_t* libifc_open() {
struct libifc_handle *h = calloc(1, sizeof(struct libifc_handle));
return h;
}


/// <summary> function used by other wrapper functions to populate _errstate when appropriate. </summary>
static int libifc_ioctlwrap_ret(unsigned long request, int rcode) {
if (rcode != 0) {
libifc_errstate.errtype = IOCTL;
libifc_errstate.ioctl_request = request;
libifc_errstate.errcode = errno;
}
return rcode;
void libifc_close(libifc_handle_t *h) {
if (h->sockets.sdkeys != NULL) {
free(h->sockets.sdkeys);
h->sockets.sdkeys = NULL;
}
if (h->sockets.sdvals != NULL) {
for (int i=0; i < h->sockets.sdindex; i++){
close(h->sockets.sdvals[i]);
}
free(h->sockets.sdvals);
h->sockets.sdvals = NULL;
}
h->sockets.sdindex = 0;
free(h);
}

/// <summary> function to wrap ioctl() and automatically populate libifc_errstate when appropriate. </summary>
static int libifc_ioctlwrap(int s, unsigned long request, struct ifreq *ifr) {
int rcode = ioctl(s, request, ifr);
return libifc_ioctlwrap_ret(request, rcode);
libifc_errtype libifc_err_errtype(libifc_handle_t *h) {
return h->error.errtype;
}

/// <summary> function to wrap ioctl(), casting ifr to caddr_t, and automatically populate libifc_errstate when appropriate. </summary>
static int libifc_ioctlwrap_caddr(int s, unsigned long request, struct ifreq *ifr) {
int rcode = ioctl(s, request, (caddr_t)ifr);
return libifc_ioctlwrap_ret(request, rcode);
int libifc_err_errno(libifc_handle_t *h) {
return h->error.errcode;
}

int libifc_err_ioctlreq(libifc_handle_t *h) {
return h->error.ioctl_request;
}


int libifc_get_description(const char *name, char **description) {
int libifc_get_description(libifc_handle_t *h, const char *name, char **description) {
struct ifreq ifr;
char *descr = NULL;
size_t descrlen = 64;
int s;
if (libifc_socket(AF_LOCAL, &s) != 0)
if (libifc_socket(h, AF_LOCAL, &s) != 0)
return -1;

strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
for (;;) {
if ((descr = reallocf(descr, descrlen)) != NULL) {
ifr.ifr_buffer.buffer = descr;
ifr.ifr_buffer.length = descrlen;
if (libifc_ioctlwrap(s, SIOCGIFDESCR, &ifr) == 0) {
if (libifc_ioctlwrap(h, s, SIOCGIFDESCR, &ifr) == 0) {
if (ifr.ifr_buffer.buffer == descr) {
if (strlen(descr) > 0) {
*description = strdup(descr);
Expand All @@ -133,40 +136,46 @@ int libifc_get_description(const char *name, char **description) {
}
} else {
free(descr);
libifc_errstate.errtype = OTHER;
libifc_errstate.errcode = ENOMEM;
h->error.errtype = OTHER;
h->error.errcode = ENOMEM;
return -1;
}
break;
}
free(descr);
libifc_errstate.errtype = OTHER;
h->error.errtype = OTHER;
h->error.errcode = 0;
return -1;
}

int libifc_set_description(const char *name, const char *newdescription) {
int libifc_set_description(libifc_handle_t *h, const char *name, const char *newdescription) {
struct ifreq ifr;
int desclen, s;
desclen = strlen(newdescription);
if (libifc_socket(AF_LOCAL, &s) != 0)
if (libifc_socket(h, AF_LOCAL, &s) != 0)
return -1; // Just return, as we can inherit error from ..._socket()

// Unset description if the new description is 0 characters long.
// TODO: Decide whether this should be an error condition instead.
if (desclen == 0)
return libifc_unset_description(name);
return libifc_unset_description(h, name);

strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));

ifr.ifr_buffer.length = desclen + 1;
ifr.ifr_buffer.buffer = strdup(newdescription);
if (ifr.ifr_buffer.buffer == NULL) {
libifc_errstate.errtype = OTHER;
libifc_errstate.errcode = ENOMEM;
h->error.errtype = OTHER;
h->error.errcode = ENOMEM;
return -1;
}

if (libifc_ioctlwrap_caddr(s, SIOCSIFDESCR, &ifr) < 0) {
/*
* TODO: Check whether this ioctl() call truncates or fails when new
* description is too long. If truncates, this function should probably
* have an error condition for this further up.
*/
if (libifc_ioctlwrap_caddr(h, s, SIOCSIFDESCR, &ifr) != 0) {
if (ifr.ifr_buffer.buffer != NULL)
free(ifr.ifr_buffer.buffer);
return -1;
Expand All @@ -176,110 +185,115 @@ int libifc_set_description(const char *name, const char *newdescription) {
return 0;
}

int libifc_unset_description(const char *name) {
int libifc_unset_description(libifc_handle_t *h, const char *name) {
struct ifreq ifr;
int s;

if (libifc_socket(AF_LOCAL, &s) != 0)
if (libifc_socket(h, AF_LOCAL, &s) != 0)
return -1;

strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
ifr.ifr_buffer.length = 0;
ifr.ifr_buffer.buffer = NULL;

if (libifc_ioctlwrap_caddr(s, SIOCSIFDESCR, &ifr) < 0) {
if (libifc_ioctlwrap_caddr(h, s, SIOCSIFDESCR, &ifr) < 0) {
return -1;
}
return 0;
}

int libifc_set_name(const char *name, const char *newname) {
int libifc_set_name(libifc_handle_t *h, const char *name, const char *newname) {
struct ifreq ifr;
char *tmpname;
int s;

if (libifc_socket(AF_LOCAL, &s) != 0)
if (libifc_socket(h, AF_LOCAL, &s) != 0)
return -1;

tmpname = strdup(newname);
if (tmpname == NULL) {
libifc_errstate.errtype = OTHER;
libifc_errstate.errcode = ENOMEM;
h->error.errtype = OTHER;
h->error.errcode = ENOMEM;
return -1;
}

strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
ifr.ifr_data = tmpname;

if (libifc_ioctlwrap_caddr(s, SIOCSIFNAME, &ifr) < 0) {
/*
* TODO: Check whether this ioctl() call truncates or fails when new
* name is too long. If truncates, this function should have an error
* condition for this further up.
*/
if (libifc_ioctlwrap_caddr(h, s, SIOCSIFNAME, &ifr) != 0) {
free(tmpname);
return -1;
}
free(tmpname);
return 0;
}

int libifc_set_mtu(const char *name, const int mtu){
int libifc_set_mtu(libifc_handle_t *h, const char *name, const int mtu){
struct ifreq ifr;
int s;

if (libifc_socket(AF_LOCAL, &s) != 0)
if (libifc_socket(h, AF_LOCAL, &s) != 0)
return -1;

strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
ifr.ifr_mtu = mtu;
if (libifc_ioctlwrap_caddr(s, SIOCSIFMTU, &ifr) < 0) {
if (libifc_ioctlwrap_caddr(h, s, SIOCSIFMTU, &ifr) < 0) {
return -1;
}
return 0;
}

int libifc_get_mtu(const char *name, int *mtu) {
int libifc_get_mtu(libifc_handle_t *h, const char *name, int *mtu) {
struct ifreq ifr;
int s;

if (libifc_socket(AF_LOCAL, &s) != 0)
if (libifc_socket(h, AF_LOCAL, &s) != 0)
return -1;

strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
if (libifc_ioctlwrap(s, SIOCGIFMTU, &ifr) == -1) {
if (libifc_ioctlwrap(h, s, SIOCGIFMTU, &ifr) == -1) {
return -1;
}
*mtu = ifr.ifr_mtu;
return 0;
}

int libifc_set_metric(const char *name, const int mtu){
int libifc_set_metric(libifc_handle_t *h, const char *name, const int mtu){
struct ifreq ifr;
int s;

if (libifc_socket(AF_LOCAL, &s) != 0)
if (libifc_socket(h, AF_LOCAL, &s) != 0)
return -1;

strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
ifr.ifr_mtu = mtu;
if (libifc_ioctlwrap_caddr(s, SIOCSIFMETRIC, &ifr) < 0) {
if (libifc_ioctlwrap_caddr(h, s, SIOCSIFMETRIC, &ifr) < 0) {
return -1;
}
return 0;
}

int libifc_get_metric(const char *name, int *metric) {
int libifc_get_metric(libifc_handle_t *h, const char *name, int *metric) {
struct ifreq ifr;
int s;

if (libifc_socket(AF_LOCAL, &s) != 0)
if (libifc_socket(h, AF_LOCAL, &s) != 0)
return -1;

strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
if (libifc_ioctlwrap(s, SIOCGIFMETRIC, &ifr) == -1) {
if (libifc_ioctlwrap(h, s, SIOCGIFMETRIC, &ifr) == -1) {
return -1;
}
*metric = ifr.ifr_metric;
return 0;
}

int libifc_set_capability(const char *name, const int capability) {
int libifc_set_capability(libifc_handle_t *h, const char *name, const int capability) {
struct ifreq ifr;
struct libifc_capabilities ifcap;
int flags;
Expand All @@ -289,10 +303,10 @@ int libifc_set_capability(const char *name, const int capability) {
* Get the socket early, as if this fails
* there's no point to _get_capability().
*/
if (libifc_socket(AF_LOCAL, &s) != 0)
if (libifc_socket(h, AF_LOCAL, &s) != 0)
return -1;

if (libifc_get_capability(name, &ifcap) != 0)
if (libifc_get_capability(h, name, &ifcap) != 0)
return -1;

value = capability;
Expand All @@ -310,23 +324,23 @@ int libifc_set_capability(const char *name, const int capability) {
* set for this request.
*/
ifr.ifr_reqcap = flags;
if (libifc_ioctlwrap_caddr(s, SIOCSIFCAP, &ifr) < 0) {
if (libifc_ioctlwrap_caddr(h, s, SIOCSIFCAP, &ifr) < 0) {
return -1;
}
return 0;
}

// Todo: convert 'capability' to struct libifc_capabilities
int libifc_get_capability(const char *name, struct libifc_capabilities *capability) {
int libifc_get_capability(libifc_handle_t *h, const char *name, struct libifc_capabilities *capability) {
struct ifreq ifr;
int s;

if (libifc_socket(AF_LOCAL, &s) != 0)
if (libifc_socket(h, AF_LOCAL, &s) != 0)
return -1;

strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));

if (libifc_ioctlwrap_caddr(s, SIOCGIFCAP, &ifr) < 0) {
if (libifc_ioctlwrap_caddr(h, s, SIOCGIFCAP, &ifr) < 0) {
return -1;
}
capability->curcap = ifr.ifr_curcap;
Expand Down

0 comments on commit 6855998

Please sign in to comment.