Skip to content

Commit ec9e13c

Browse files
author
David Sommerseth
committed
Completed implementing the new Python get_interface_info() function.
It will return a list of Python etherinfo objects. These objects have the following properties: .device - Device name .mac_address - Hardware address .ipv4_address .ipv4_netmask .ipv4_broadcast .ipv6_address .ipv6_netmask In addition, it will produce a human readable output if these objects are treated as strings. It will not be possible to modify any of the properties in these objects.
1 parent 0be405b commit ec9e13c

File tree

3 files changed

+124
-17
lines changed

3 files changed

+124
-17
lines changed

python-ethtool/etherinfo_obj.c

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ PyObject *_ethtool_etherinfo_new(PyTypeObject *type, PyObject *args, PyObject *k
4141
etherinfo_py *self;
4242

4343
self = (etherinfo_py *)type->tp_alloc(type, 0);
44-
if (self != NULL) {
45-
}
4644
return (PyObject *)self;
4745
}
4846

@@ -58,12 +56,25 @@ PyObject *_ethtool_etherinfo_new(PyTypeObject *type, PyObject *args, PyObject *k
5856
*/
5957
int _ethtool_etherinfo_init(etherinfo_py *self, PyObject *args, PyObject *kwds)
6058
{
61-
self->info = (struct etherinfo *) malloc(sizeof(struct etherinfo)+2);
62-
memset(self->info, 0, sizeof(struct etherinfo)+2);
63-
self->info->device = strdup("test");
59+
static char *etherinfo_kwlist[] = {"etherinfo_ptr", NULL};
60+
PyObject *ethinf_ptr = NULL;
61+
62+
if( !PyArg_ParseTupleAndKeywords(args, kwds, "O", etherinfo_kwlist, &ethinf_ptr)) {
63+
PyErr_SetString(PyExc_AttributeError, "Invalid data pointer to constructor");
64+
return -1;
65+
}
66+
self->info = (struct etherinfo *) PyCObject_AsVoidPtr(ethinf_ptr);
6467
return 0;
6568
}
6669

70+
/**
71+
* Null safe PyString_FromString() wrapper. If input string is NULL, a False value will be returned
72+
*
73+
* @param str Input C string (char *)
74+
*
75+
* @return Returns a PyObject with either the input string wrapped up, or a Python False value.
76+
*/
77+
#define RETURN_STRING(str) (str ? PyString_FromString(str) : Py_False);
6778

6879
/**
6980
* ethtool.etherinfo function for retrieving data from a Python object.
@@ -83,17 +94,17 @@ PyObject *_ethtool_etherinfo_getter(etherinfo_py *self, PyObject *attr_o)
8394
}
8495

8596
if( strcmp(attr, "device") == 0 ) {
86-
return PyString_FromString(self->info->device);
97+
return RETURN_STRING(self->info->device);
8798
} else if( strcmp(attr, "mac_address") == 0 ) {
88-
return PyString_FromString(self->info->hwaddress);
99+
return RETURN_STRING(self->info->hwaddress);
89100
} else if( strcmp(attr, "ipv4_address") == 0 ) {
90-
return PyString_FromString(self->info->ipv4_address);
101+
return RETURN_STRING(self->info->ipv4_address);
91102
} else if( strcmp(attr, "ipv4_netmask") == 0 ) {
92103
return PyInt_FromLong(self->info->ipv4_netmask);
93104
} else if( strcmp(attr, "ipv4_broadcast") == 0 ) {
94-
return PyString_FromString(self->info->ipv4_broadcast);
105+
return RETURN_STRING(self->info->ipv4_broadcast);
95106
} else if( strcmp(attr, "ipv6_address") == 0 ) {
96-
return PyString_FromString(self->info->ipv6_address);
107+
return RETURN_STRING(self->info->ipv6_address);
97108
} else if( strcmp(attr, "ipv6_netmask") == 0 ) {
98109
return PyInt_FromLong(self->info->ipv6_netmask);
99110
}
@@ -119,3 +130,46 @@ int _ethtool_etherinfo_setter(etherinfo_py *self, PyObject *attr_o, PyObject *va
119130
}
120131

121132

133+
/**
134+
* Creates a human readable format of the information when object is being treated as a string
135+
*
136+
* @param self
137+
*
138+
* @return Returns a PyObject with a string with all of the information
139+
*/
140+
PyObject *_ethtool_etherinfo_str(etherinfo_py *self)
141+
{
142+
PyObject *ret = NULL;
143+
144+
if( !self || !self->info ) {
145+
PyErr_SetString(PyExc_AttributeError, "No data available");
146+
return NULL;
147+
}
148+
149+
ret = PyString_FromFormat("Device %s:\n", self->info->device);
150+
if( self->info->hwaddress ) {
151+
PyObject *tmp = PyString_FromFormat("\tMAC address: %s\n", self->info->hwaddress);
152+
PyString_Concat(&ret, tmp);
153+
}
154+
155+
if( self->info->ipv4_address ) {
156+
PyObject *tmp = PyString_FromFormat("\tIPv4 address: %s/%i",
157+
self->info->ipv4_address,
158+
self->info->ipv4_netmask);
159+
if( self->info->ipv4_broadcast ) {
160+
PyObject *tmp2 = PyString_FromFormat(" Broadcast: %s",
161+
self->info->ipv4_broadcast);
162+
PyString_Concat(&tmp, tmp2);
163+
}
164+
PyString_Concat(&tmp, PyString_FromString("\n"));
165+
PyString_Concat(&ret, tmp);
166+
}
167+
168+
if( self->info->ipv6_address ) {
169+
PyObject *tmp = PyString_FromFormat("\tIPv6 address: %s/%i\n",
170+
self->info->ipv6_address,
171+
self->info->ipv6_netmask);
172+
PyString_Concat(&ret, tmp);
173+
}
174+
return ret;
175+
}

python-ethtool/etherinfo_obj.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ PyObject *_ethtool_etherinfo_new(PyTypeObject *, PyObject *, PyObject *);
2020
int _ethtool_etherinfo_init(etherinfo_py *, PyObject *, PyObject *);
2121
PyObject *_ethtool_etherinfo_getter(etherinfo_py *, PyObject *);
2222
int _ethtool_etherinfo_setter(etherinfo_py *, PyObject *, PyObject *);
23+
PyObject *_ethtool_etherinfo_str(etherinfo_py *self);
2324

2425
/**
2526
* This is required by Python, which lists all accessible methods
@@ -73,7 +74,7 @@ PyTypeObject ethtool_etherinfoType = {
7374
0, /*tp_as_mapping*/
7475
0, /*tp_hash */
7576
0, /*tp_call*/
76-
0, /*tp_str*/
77+
(reprfunc)_ethtool_etherinfo_str, /*tp_str*/
7778
(getattrofunc)_ethtool_etherinfo_getter, /*tp_getattro*/
7879
(setattrofunc)_ethtool_etherinfo_setter, /*tp_setattro*/
7980
0, /*tp_as_buffer*/

python-ethtool/ethtool.c

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,6 @@ typedef __uint8_t u8;
4545

4646
#define _PATH_PROCNET_DEV "/proc/net/dev"
4747

48-
struct etherinfo *ethernet_devices = NULL;
49-
int etherinfo_cache_dirty = 0;
50-
5148
static PyObject *get_active_devices(PyObject *self __unused, PyObject *args __unused)
5249
{
5350
PyObject *list;
@@ -226,10 +223,9 @@ static PyObject *get_ipaddress(PyObject *self __unused, PyObject *args)
226223
static PyObject *get_ipaddresses(PyObject *self __unused, PyObject *args) {
227224
PyObject *devlist = NULL;
228225
struct etherinfo *ethptr = NULL;
226+
struct etherinfo *ethernet_devices = NULL;
229227

230-
if( ethernet_devices == NULL ) {
231-
ethernet_devices = get_etherinfo();
232-
}
228+
ethernet_devices = get_etherinfo();
233229

234230
devlist = PyList_New(0);
235231
for( ethptr = ethernet_devices; ethptr->next != NULL; ethptr = ethptr->next) {
@@ -248,6 +244,57 @@ static PyObject *get_ipaddresses(PyObject *self __unused, PyObject *args) {
248244
PyList_Append(devlist, dev);
249245
}
250246
}
247+
free_etherinfo(ethernet_devices);
248+
249+
return devlist;
250+
}
251+
252+
253+
/**
254+
* Retrieves the current information about all interfaces. All interfaces will be
255+
* returned as a list of objects per interface.
256+
*
257+
* @param self Not used
258+
* @param args Python arguments
259+
*
260+
* @return Python list of objects on success, otherwise NULL.
261+
*/
262+
static PyObject *get_interfaceinfo(PyObject *self __unused, PyObject *args) {
263+
PyObject *devlist = NULL, *ethinf_py = NULL;
264+
struct etherinfo *devinfo = NULL, *ptr = NULL;
265+
266+
devinfo = get_etherinfo();
267+
if( !devinfo ) {
268+
PyErr_SetString(PyExc_OSError, strerror(errno));
269+
return NULL;
270+
}
271+
272+
/* Slice up the etherinfo struct and populate individual objects with
273+
* the current ethernet information.
274+
*/
275+
devlist = PyList_New(0);
276+
while( devinfo->next != NULL ) {
277+
/* Get copy of pointers, before we start slicing it up */
278+
ptr = devinfo->next; /* Fetch the pointer to the next element first */
279+
devinfo->next = NULL; /* Make the current slice do not point anywhere else */
280+
281+
/* Instantiate a new etherinfo object with the device information */
282+
ethinf_py = PyCObject_FromVoidPtr(devinfo, NULL);
283+
if( ethinf_py ) {
284+
/* Prepare the argument list for the object constructor */
285+
PyObject *args = PyTuple_New(1);
286+
PyTuple_SetItem(args, 0, ethinf_py);
287+
288+
/* Create the object */
289+
PyObject *dev = PyObject_CallObject((PyObject *)&ethtool_etherinfoType, args);
290+
PyList_Append(devlist, dev);
291+
}
292+
devinfo = ptr; /* Go to the next element */
293+
}
294+
/* clean up headers which might not be used or considered interesting */
295+
if( devinfo != NULL ) {
296+
free_etherinfo(devinfo);
297+
}
251298

252299
return devlist;
253300
}
@@ -816,6 +863,11 @@ static struct PyMethodDef PyEthModuleMethods[] = {
816863
.ml_meth = (PyCFunction)get_ipaddresses,
817864
.ml_flags = METH_VARARGS,
818865
},
866+
{
867+
.ml_name = "get_interface_info",
868+
.ml_meth = (PyCFunction)get_interfaceinfo,
869+
.ml_flags = METH_VARARGS,
870+
},
819871
{
820872
.ml_name = "get_netmask",
821873
.ml_meth = (PyCFunction)get_netmask,

0 commit comments

Comments
 (0)