I'm trying to debug a code that is using a libevent library. In that library, there is a function event_new that is suppose to create an event_cb. Somehow after I dispatch the event base, the event_cb cannot be called or accessed. This problem only happens on hpux itanium. This code works on hpux pa-risc, Redhat, AIX, and Solaris. Is there any certain thing that need to be set?
This is part of the code
int ttypread (int fd, Header *h, char **buf)
{
int c,k;
struct user_data user_data;
struct bufferevent *in_buffer;
struct event_config *evconfig;
log_debug("inside ttypread");
in_buffer = NULL;
user_data.fd = fd;
user_data.h = h;
user_data.buf = buf;
log_debug("from user_data, fd = %d",user_data.fd); //the log_debug is a debugging function for me to check the value sent by the system. I use it to compare between each platform
log_debug("from user_data, buf = %s",user_data.buf);
log_debug("from user_data, h.len = %d",user_data.h->len);
log_debug("from user_data, h.type = %d",user_data.h->type);
evconfig = event_config_new();
if (evconfig == NULL) {
log_error("event_config_new failed");
return -1;
}
if (event_config_require_features(evconfig, EV_FEATURE_FDS)!=0) {
log_error("event_config_require_features failed");
return -1;
}
base = event_base_new_with_config(evconfig);
if (!base) {
log_error("ttypread:event_base_new failed");
return -1;
}
const char* method; //these 3 lines are the new line edited
method = event_base_get_method(base);
log_debug("ttyread is using method = %s",method);
ev = event_new(base, fd, EV_READ|EV_PERSIST, ttypread_event_cb, &user_data);
c = event_add(ev, NULL);
log_debug("ttypread passed event_add with c value is %d",c);
in_buffer = bufferevent_socket_new(base, STDIN_FILENO, BEV_OPT_CLOSE_ON_FREE);
log_debug("ttypread passed bufferevent_socket_new");
if(in_buffer == NULL){
log_debug("problem with bufferevent_socket_new");
}
bufferevent_setcb(in_buffer, in_read_cb, NULL, in_event_cb, NULL);
bufferevent_disable(in_buffer, EV_WRITE);
bufferevent_enable(in_buffer, EV_READ);
k =event_base_dispatch(base);
log_debug("event_base have been dispatched"); //when looking at the debugging file, the other plaform will go to ttypread_event_cb function. But for hpux itanium, it stays here.
if (k == 0){
log_debug("event_base_dispatch returned 0");
} else if (k == -1){
log_debug("event_base_dispatch returned -1");
} else {
log_debug("event_base_dispatch returned 1");
}
event_base_free(base);
event_free(ev);
log_debug("finish ttypread");
log_debug("ttypread_ret will return [%d]",ttypread_ret);
return ttypread_ret;
}
void ttypread_event_cb(evutil_socket_t fd, short events, void *arg)
{
int nread;
struct timeval t;
struct user_data *user_data;
user_data = (struct user_data*)arg;
nread = 0;
log_debug("inside ttypread_event_cb");
if (events & EV_READ) {
log_debug("got events & EV_READ");
nread = ttyread(fd, user_data->h, user_data->buf);
if (nread == -1) {
ttypread_ret = -1;
event_del(ev);
event_base_loopexit(base, NULL);
} else if (nread == 0) {
if (access(input_filename, F_OK)!=0) {
log_debug("cannot access [%s]",input_filename);
tcsetattr(0, TCSANOW, &old); /* Return terminal state */
exit(EXIT_SUCCESS);
}
t.tv_sec = 0;
t.tv_usec = 250000;
select(0, 0, 0, 0, &t);
} else {
ttypread_ret = 1;
event_del(ev);
event_base_loopexit(base, NULL);
}
}
else if (events & EV_WRITE) {
log_debug("got events & EV_WRITE");
}
}
Not sure if this help. But just some info on the hpux itanium
uname -a = HP-UX hpux-ita B.11.23 U ia64
If you need any additional info or other declaration on function, just leave a comment and I will edit the question.
EDIT : i've added a function inside ttypread. Somehow for hpux itanium its returning devpoll while other platform are returning poll. Im not sure if this is the problem. But if that is so, is there any way for me to change it?
After checking the result from event_base_get_method, I found out that only on my hpux-itanium used devpoll method. This is how I solve it.
char string[8] = "devpoll";
struct user_data user_data;
struct bufferevent *in_buffer;
struct event_config *evconfig;
const char *method;
const char *devpoll;
devpoll = string;
in_buffer = NULL;
user_data.fd = fd;
user_data.h = h;
user_data.buf = buf;
evconfig = event_config_new();
if (evconfig == NULL) {
log_error("event_config_new failed");
return -1;
}
if (event_config_require_features(evconfig, EV_FEATURE_FDS)!=0) {
log_error("event_config_require_features failed");
return -1;
}
if (event_config_avoid_method(evconfig,devpoll) != 0)
{
log_error("Failed to ignore devpoll method");
}
Force the libevent to ignore using devpoll and use poll instead.
Related
I have a program running on a QEMU VM. The program running inside this VM gets notified by a program on the host via interrupts and using QEMU ivshmem. The program on the host creates an eventfd and sends this file descriptor to QEMU when the VM starts. The program in the guest then opens a VFIO group device and sets an interrupt request fd on this device. We can then add the interrupt fd to epoll and epoll_wait to wait for notifications from the host.
The thing is that I want a 1-1 matching between the times the host writes to the eventfd and the number of events that are signaled in epoll_wait. For this I decided to use EFD_SEMAPHORE for the evenfds on the host and the guest. From my understanding, every time I write an 8 byte integer with value 1, the eventfd_counter is incremented by 1. Then every time the eventfd is read, the counter is decremented by 1 (different from a regular eventfd where each read clears the whole counter). For some reason, I am not getting the desired behaviour, so I was wondering if either eventfds with the EFD_SEMAPHORE flags are not properly supported by VFIO or QEMUs ivshmem.
Below is a simplified version of the parts I think are relevant and how I setup the notification system. I hope the code below is not too verbose. I tried to reduce the number of irrelevant parts (there is too much other code in the middle that is not particularly relevant to the problem) but not 100% sure what might be relevant or not.
Code host uses to signal guest
int ivshmem_uxsocket_send_int(int fd, int64_t i)
{
int n;
struct iovec iov = {
.iov_base = &i,
.iov_len = sizeof(i),
};
struct msghdr msg = {
.msg_name = NULL,
.msg_namelen = 0,
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = NULL,
.msg_controllen = 0,
.msg_flags = 0,
};
if ((n = sendmsg(fd, &msg, 0)) != sizeof(int64_t))
{
return -1;
}
return n;
}
int ivshmem_uxsocket_sendfd(int uxfd, int fd, int64_t i)
{
int n;
struct cmsghdr *chdr;
/* Need to pass at least one byte of data to send control data */
struct iovec iov = {
.iov_base = &i,
.iov_len = sizeof(i),
};
/* Allocate a char array but use a union to ensure that it
is aligned properly */
union {
char buf[CMSG_SPACE(sizeof(fd))];
struct cmsghdr align;
} cmsg;
memset(&cmsg, 0, sizeof(cmsg));
/* Add control data (file descriptor) to msg */
struct msghdr msg = {
.msg_name = NULL,
.msg_namelen = 0,
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = &cmsg,
.msg_controllen = sizeof(cmsg),
.msg_flags = 0,
};
/* Set message header to describe ancillary data */
chdr = CMSG_FIRSTHDR(&msg);
chdr->cmsg_level = SOL_SOCKET;
chdr->cmsg_type = SCM_RIGHTS;
chdr->cmsg_len = CMSG_LEN(sizeof(int));
memcpy(CMSG_DATA(chdr), &fd, sizeof(fd));
if ((n = sendmsg(uxfd, &msg, 0)) != sizeof(i))
{
return -1;
}
return n;
}
/* SETUP IVSHMEM WITH QEMU AND PASS THE EVENTFD USED TO
NOTIFY THE GUEST */
int ivshmem_uxsocket_accept()
{
int ret;
int cfd, ifd, nfd;
int64_t version = IVSHMEM_PROTOCOL_VERSION;
uint64_t hostid = HOST_PEERID;
int vmid = 0
/* Accept connection from qemu ivshmem */
if ((cfd = accept(uxfd, NULL, NULL)) < 0)
{
return -1;
}
/* Send protocol version as required by qemu ivshmem */
ret = ivshmem_uxsocket_send_int(cfd, version);
if (ret < 0)
{
return -1;
}
/* Send vm id to qemu */
ret = ivshmem_uxsocket_send_int(cfd, vmid);
if (ret < 0)
{
return -1;
}
/* Send shared memory fd to qemu */
ret = ivshmem_uxsocket_sendfd(cfd, shm_fd, -1);
if (ret < 0)
{
return -1;
}
/* Eventfd used by guest to notify host */
if ((nfd = eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK)) < 0)
{
return -1;
}
/* Ivshmem protocol requires to send host id
with the notify fd */
ret = ivshmem_uxsocket_sendfd(cfd, nfd, hostid);
if (ret < 0)
{
return -1;
}
/* THIS IS THE EVENTFD OF INTEREST TO US: USED BY HOST
TO NOTIFY GUEST */
if ((ifd = eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK)) < 0)
{
return -1;
}
ret = ivshmem_uxsocket_sendfd(cfd, ifd, vmid);
if (ret < 0)
{
return -1;
}
if (epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &ev) < 0)
{
return -1;
}
return 0;
}
/* NOW EVERY TIME WE WANT TO NOTIFY THE GUEST
WE CALL THE FOLLOWING FUNCTION */
int notify_guest(int fd)
{
int ret;
uint64_t buf = 1;
ret = write(fd, &buf, sizeof(uint64_t));
if (ret < sizeof(uint64_t))
{
return -1;
}
return 0;
}
Code guest uses to receive notifications from host
/* THIS FUNCTION SETS THE IRQ THAT RECEIVES THE
NOTIFICATIONS FROM THE HOST */
int vfio_set_irq(int dev)
{
int fd;
struct vfio_irq_set *irq_set;
char buf[sizeof(struct vfio_irq_set) + sizeof(int)];
if ((fd = eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK)) < 0)
{
return -1;
}
irq_set = (struct vfio_irq_set *) buf;
irq_set->argsz = sizeof(buf);
irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
irq_set->index = 2;
irq_set->start = 0;
irq_set->count = 1;
memcpy(&irq_set->data, &fd, sizeof(int));
if (ioctl(dev, VFIO_DEVICE_SET_IRQS, irq_set) < 0)
{
return -1;
}
return irq_fd;
}
/* The guest sets up the ivshmem region from QEMU and sets the
interrupt request. */
int vfio_init()
{
int cont, group, irq_fd;
struct epoll_event ev;
struct vfio_group_status g_status = { .argsz = sizeof(g_status) };
struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
/* Create vfio container */
if ((cont = open("/dev/vfio/vfio", O_RDWR)) < 0)
{
return -1;
}
/* Check API version of container */
if (ioctl(cont, VFIO_GET_API_VERSION) != VFIO_API_VERSION)
{
return -1;
}
if (!ioctl(cont, VFIO_CHECK_EXTENSION, VFIO_NOIOMMU_IOMMU))
{
return -1;
}
/* Open the vfio group */
if((group = open(VFIO_GROUP, O_RDWR)) < 0)
{
return -1;
}
/* Test if group is viable and available */
ioctl(group, VFIO_GROUP_GET_STATUS, &g_status);
if (!(g_status.flags & VFIO_GROUP_FLAGS_VIABLE))
{
return -1;
}
/* Add group to container */
if (ioctl(group, VFIO_GROUP_SET_CONTAINER, &cont) < 0)
{
return -1;
}
/* Enable desired IOMMU model */
if (ioctl(cont, VFIO_SET_IOMMU, VFIO_NOIOMMU_IOMMU) < 0)
{
return -1;
}
/* Get file descriptor for device */
if ((dev = ioctl(group, VFIO_GROUP_GET_DEVICE_FD, VFIO_PCI_DEV)) < 0)
{
return -1;
}
/* Get device info */
if (ioctl(dev, VFIO_DEVICE_GET_INFO, &device_info) < 0)
{
return -1;
}
/* Set interrupt request fd */
if ((irq_fd = vfio_set_irq(dev)) < 0)
{
return -1
}
/* Add interrupt request fd to interest list */
if (vfio_subscribe_irq() < 0)
{
return -1;
}
/* Do other shm setup stuff not related to the interrupt
request */
ev.events = EPOLLIN;
ev.data.ptr = EP_NOTIFY;
ev.data.fd = irq_fd;
if (epoll_ctl(epfd, EPOLL_CTL_ADD, irq_fd, &ev) != 0)
{
return -1;
}
return 0;
}
int ivshmem_drain_evfd(int fd)
{
int ret;
uint64_t buf;
ret = read(fd, &buf, sizeof(uint64_t));
if (ret == 0)
{
return -1;
}
return ret;
}
/* I should get every notification from the host here,
but it seems that not all notifications are going
through. The number of calls to notify_guest does not
match the number of events received from epoll_wait
here */
int notify_poll()
{
int i, n;
struct epoll_event evs[32];
n = epoll_wait(epfd, evs, 32, 0);
for (i = 0; i < n; i++)
{
if (evs[i].events & EPOLLIN)
{
/* Drain evfd */
drain_evfd(irq_fd);
/* Handle notification ... */
handle();
}
}
}
I am trying to group the operation under libmodbus for Mod-bus connection and get-value into two simpler function as below.
However, it always cause Segmentation fault (core dumped) when I try to get value from the device.(get_float, modbus_read_registers)
Can anyone tell me how to fix it?
int connect(char *ip_addr, struct timeval timeout, modbus_t *ctx){
int fail = 0;
ctx = modbus_new_tcp(ip_addr, MODBUS_SERVER_PORT);
modbus_set_slave(ctx, MODBUS_DEVICE_ID);
modbus_set_debug(ctx, MODBUS_DEBUG);
timeout.tv_sec = MODBUS_TIMEOUT_SEC;
timeout.tv_usec = MODBUS_TIMEOUT_USEC;
modbus_get_byte_timeout(ctx, &timeout.tv_sec, &timeout.tv_usec);
timeout.tv_sec = MODBUS_TIMEOUT_SEC;
timeout.tv_usec = MODBUS_TIMEOUT_USEC;
modbus_set_response_timeout(ctx, timeout.tv_sec, timeout.tv_usec);
fail = modbus_connect(ctx);
if (fail == -1) {
fprintf(stderr, "Connection failed: %s\n",
modbus_strerror(errno));
modbus_free(ctx);
fail = -1;
}
return fail;
}
int get_float(modbus_t *ctx, uint16_t addr, float *val){
int fail = 0;
__uint16_t value[2];
printf("1\n");
fail = modbus_read_registers(ctx, (addr-1), 2, value);
printf("2\n");
if(fail <= 0) {
fprintf(stderr, "Reading error(%d): %s\n", addr, modbus_strerror(errno));
} else {
*val = modbus_get_float_abcd(value);
}
return fail;
}
Besides, I can successfully run the similar code when I put them in same function as below:
int connect_n_getFloat(char *ip_addr, uint16_t addr, float *val){
int fail = 0;
modbus_t *ctx = modbus_new_tcp(ip_addr, MODBUS_SERVER_PORT);
ctxConfig(ctx);
if (modbus_connect(ctx) == 0) {
__uint16_t value[2];
if(modbus_read_registers(ctx, (addr-1), 2, value) > 0) {
*val = modbus_get_float_abcd(value);
} else {
fprintf(stderr, "Reading error(%d): %s\n", addr, modbus_strerror(errno));
fail = -1;
}
} else {
fprintf(stderr, "Connection failed: %s\n",
modbus_strerror(errno));
modbus_free(ctx);
fail = -1;
}
return fail;
}
You're passing a context pointer to the connect function, but should be passing a pointer to a pointer, so you can return the allocated context and continue using it in further calls.
Change the function signature, and ctx usage, from
int connect(char *ip_addr, struct timeval timeout, modbus_t *ctx) {
int fail = 0;
ctx = modbus_new_tcp(ip_addr, MODBUS_SERVER_PORT);
to
int connect(char *ip_addr, struct timeval timeout, modbus_t **ctx) {
int fail = 0;
*ctx = modbus_new_tcp(ip_addr, MODBUS_SERVER_PORT);
This also explains why it works when you put them in the same function.
I'm trying to send nested attributes from user space to kernel using generic netlink, the function nl_send_auto() returns 52 (which was supposed to be the numbers of bytes sent to kernel) but the kernel isn't receiving the messages. Is there some problem with my approach? Here is the code that I wrote on user space:
int err = -1;
struct nl_msg *msg;
struct nlattr *attr;
struct nl_sock *sock;
int family;
int send = 0;
if ((sock = nl_socket_alloc()) == NULL)
return err;
if ((err = genl_connect(sock)))
return err;
if ((family = genl_ctrl_resolve(sock, FAMILY)) < 0)
return family;
if ((msg = nlmsg_alloc()) == NULL)
return err;
if ((genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, FAMILY, 0,
NLM_F_REQUEST, CREATE_STATE, 1)) == NULL)
return err;
if (!(attr = nla_nest_start(msg, KLUA_NL_STATE))){
nla_nest_cancel(msg, attr);
return err;
}
if ((ret = nla_put_string(msg, STATE_NAME, cmd->name)) ||
(ret = nla_put_u32(msg, MAX_ALLOC, cmd->maxalloc)) ||
(ret = nla_put_u32(msg, CURR_ALLOC, cmd->curralloc))
)
return err;
nla_nest_end(msg, attr);
if ((send = nl_send_auto(ctrl->sock, msg)) < 0)
return send;
printf("All done sended %d bytes\n", send);
nlmsg_free(msg);
This code prints 52, which is the bytes sent to kernel;
The FAMILY macro is defined as (both in kernel and user space):
#define FAMILY "family"
My netlink attributes are (both for kernel and user space):
enum {
KLUA_NL_STATE,
STATE_NAME,
MAX_ALLOC,
CURR_ALLOC,
ATTR_COUNT,
#define ATTR_MAX (ATTR_COUNT - 1)
};
My enum for operation is:
enum {
CREATE_STATE = 16,
};
And my kernel code is:
struct nla_policy lunatik_policy[ATTR_MAX] = {
[KLUA_NL_STATE] = { .type = NLA_NESTED },
};
static int klua_create_state(struct sk_buff *buff, struct genl_info *info);
static const struct genl_ops l_ops[] = {
{
.cmd = CREATE_STATE,
.doit = klua_create_state,
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0)
/*Before kernel 5.2.0, each operation has its own policy*/
.policy = lunatik_policy
#endif
},
};
#define KLUA_NL_STATE_ATTRS_COUNT 3
struct genl_family lunatik_family = {
.name = FAMILY,
.version = 1,
.maxattr = ATTR_MAX,
.netnsok = true,
.policy = lunatik_policy,
.module = THIS_MODULE,
.ops = l_ops,
.n_ops = ARRAY_SIZE(l_ops),
};
static int klua_create_state(struct sk_buff *buff, struct genl_info *info)
{
pr_info("I received the message\n");
return 0;
}
This code doesn't print anything on dmesg, and I would like to know why.
You actual problems
During Linux 5.2 refactors, the semantics of the NLA_F_NESTED flag changed somewhat. It appears you now need to always include it when you call nla_nest_start():
if (!(attr = nla_nest_start(msg, KLUA_NL_STATE))){
...
}
Should be
if (!(attr = nla_nest_start(msg, NLA_F_NESTED | KLUA_NL_STATE))){
...
}
Yes, I'm well aware the libnl library should obviously do this for you, and will perhaps do so in the future, but unfortunately this is where we are now.
Also:
enum {
KLUA_NL_STATE,
...
};
Attribute zero is always reserved. You need to change that into
enum {
KLUA_NL_STATE = 1,
...
};
Just FYI: operation zero is also reserved, so it's fortunate that you chose 16. But do keep it in mind in the future.
Syntactic issues
These are probably just copy-paste errors, but I'm including them anyway for the benefit on other people landing in this page looking for examples.
if ((genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, FAMILY, 0,
NLM_F_REQUEST, CREATE_STATE, 1)) == NULL)
return err;
Should be
if ((genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, family, 0,
NLM_F_REQUEST, CREATE_STATE, 1)) == NULL)
return err;
Also:
if ((ret = nla_put_string(msg, STATE_NAME, cmd->name)) ||
(ret = nla_put_u32(msg, MAX_ALLOC, cmd->maxalloc)) ||
(ret = nla_put_u32(msg, CURR_ALLOC, cmd->curralloc))
)
return err;
Should be
if ((err = nla_put_string(msg, STATE_NAME, cmd->name)) ||
(err = nla_put_u32(msg, MAX_ALLOC, cmd->maxalloc)) ||
(err = nla_put_u32(msg, CURR_ALLOC, cmd->curralloc))
)
return err;
Also:
if ((send = nl_send_auto(ctrl->sock, msg)) < 0)
return send;
Should be
if ((send = nl_send_auto(sock, msg)) < 0)
return send;
I'm trying to use nl80211.h for scanning access points for a simple WLAN manager. I can't find any example code and only documentation I can find is kerneldoc. I have been trying to study from iw and wpa_supplicant source but it's rather complex.
This is only documentation I can find:
NL80211_CMD_GET_SCAN get scan results
NL80211_CMD_TRIGGER_SCAN trigger a new scan with the given parameters
NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
probe requests at CCK rate or not.
How can I scan access points with nl80211? I think I need to use enum nl80211_commands {NL80211_CMD_GET_SCAN NL80211_CMD_TRIGGER_SCAN}. How can I use them?
I know this is an old question but I ran across it while I was trying to do the same thing. Being new to C and libnl I struggled to get a simple C program to just spit out access points. I'm posting this here for others who were also trying to write a simple program. iw was a great reference but it was challenging following the code around since it does so much more than scan for access points.
/*
* scan_access_points.c: Prints all detected access points with wlan0 using NL80211 (netlink).
*
* Only works on network interfaces whose drivers are compatible with Netlink. Test this by running `iw list`.
*
* Since only privileged users may submit NL80211_CMD_TRIGGER_SCAN, you'll have to run the compiled program as root.
*
* Build with: gcc $(pkg-config --cflags --libs libnl-genl-3.0) scan_access_points.c
*
* Raspbian prerequisites:
* sudo apt-get install libnl-genl-3-dev
*
* Resources:
* http://git.kernel.org/cgit/linux/kernel/git/jberg/iw.git/tree/scan.c
* http://stackoverflow.com/questions/21601521/how-to-use-the-libnl-library-to-trigger-nl80211-commands
* http://stackoverflow.com/questions/23760780/how-to-send-single-channel-scan-request-to-libnl-and-receive-single-
*
* Expected output (as root):
* NL80211_CMD_TRIGGER_SCAN sent 36 bytes to the kernel.
* Waiting for scan to complete...
* Got NL80211_CMD_NEW_SCAN_RESULTS.
* Scan is done.
* NL80211_CMD_GET_SCAN sent 28 bytes to the kernel.
* 47:be:34:f0:bb:be, 2457 MHz, NETGEAR16
* 6b:db:ed:85:ef:42, 2432 MHz, NETGEAR31
* d8:06:ef:a7:f9:80, 2412 MHz, ATT912
* a7:0d:af:0a:19:08, 2462 MHz, ATT185
*
* Expected output (without root):
* NL80211_CMD_TRIGGER_SCAN sent 36 bytes to the kernel.
* Waiting for scan to complete...
* error_handler() called.
* WARNING: err has a value of -1.
* ERROR: nl_recvmsgs() returned -28 (Operation not permitted).
* do_scan_trigger() failed with -28.
*
*/
#include <errno.h>
#include <netlink/errno.h>
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <linux/nl80211.h>
struct trigger_results {
int done;
int aborted;
};
struct handler_args { // For family_handler() and nl_get_multicast_id().
const char *group;
int id;
};
static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) {
// Callback for errors.
printf("error_handler() called.\n");
int *ret = arg;
*ret = err->error;
return NL_STOP;
}
static int finish_handler(struct nl_msg *msg, void *arg) {
// Callback for NL_CB_FINISH.
int *ret = arg;
*ret = 0;
return NL_SKIP;
}
static int ack_handler(struct nl_msg *msg, void *arg) {
// Callback for NL_CB_ACK.
int *ret = arg;
*ret = 0;
return NL_STOP;
}
static int no_seq_check(struct nl_msg *msg, void *arg) {
// Callback for NL_CB_SEQ_CHECK.
return NL_OK;
}
static int family_handler(struct nl_msg *msg, void *arg) {
// Callback for NL_CB_VALID within nl_get_multicast_id(). From http://sourcecodebrowser.com/iw/0.9.14/genl_8c.html.
struct handler_args *grp = arg;
struct nlattr *tb[CTRL_ATTR_MAX + 1];
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
struct nlattr *mcgrp;
int rem_mcgrp;
nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
if (!tb[CTRL_ATTR_MCAST_GROUPS]) return NL_SKIP;
nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp) { // This is a loop.
struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1];
nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp), nla_len(mcgrp), NULL);
if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME] || !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]) continue;
if (strncmp(nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]), grp->group,
nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]))) {
continue;
}
grp->id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]);
break;
}
return NL_SKIP;
}
int nl_get_multicast_id(struct nl_sock *sock, const char *family, const char *group) {
// From http://sourcecodebrowser.com/iw/0.9.14/genl_8c.html.
struct nl_msg *msg;
struct nl_cb *cb;
int ret, ctrlid;
struct handler_args grp = { .group = group, .id = -ENOENT, };
msg = nlmsg_alloc();
if (!msg) return -ENOMEM;
cb = nl_cb_alloc(NL_CB_DEFAULT);
if (!cb) {
ret = -ENOMEM;
goto out_fail_cb;
}
ctrlid = genl_ctrl_resolve(sock, "nlctrl");
genlmsg_put(msg, 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0);
ret = -ENOBUFS;
NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
ret = nl_send_auto_complete(sock, msg);
if (ret < 0) goto out;
ret = 1;
nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret);
nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &ret);
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, family_handler, &grp);
while (ret > 0) nl_recvmsgs(sock, cb);
if (ret == 0) ret = grp.id;
nla_put_failure:
out:
nl_cb_put(cb);
out_fail_cb:
nlmsg_free(msg);
return ret;
}
void mac_addr_n2a(char *mac_addr, unsigned char *arg) {
// From http://git.kernel.org/cgit/linux/kernel/git/jberg/iw.git/tree/util.c.
int i, l;
l = 0;
for (i = 0; i < 6; i++) {
if (i == 0) {
sprintf(mac_addr+l, "%02x", arg[i]);
l += 2;
} else {
sprintf(mac_addr+l, ":%02x", arg[i]);
l += 3;
}
}
}
void print_ssid(unsigned char *ie, int ielen) {
uint8_t len;
uint8_t *data;
int i;
while (ielen >= 2 && ielen >= ie[1]) {
if (ie[0] == 0 && ie[1] >= 0 && ie[1] <= 32) {
len = ie[1];
data = ie + 2;
for (i = 0; i < len; i++) {
if (isprint(data[i]) && data[i] != ' ' && data[i] != '\\') printf("%c", data[i]);
else if (data[i] == ' ' && (i != 0 && i != len -1)) printf(" ");
else printf("\\x%.2x", data[i]);
}
break;
}
ielen -= ie[1] + 2;
ie += ie[1] + 2;
}
}
static int callback_trigger(struct nl_msg *msg, void *arg) {
// Called by the kernel when the scan is done or has been aborted.
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
struct trigger_results *results = arg;
//printf("Got something.\n");
//printf("%d\n", arg);
//nl_msg_dump(msg, stdout);
if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED) {
printf("Got NL80211_CMD_SCAN_ABORTED.\n");
results->done = 1;
results->aborted = 1;
} else if (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS) {
printf("Got NL80211_CMD_NEW_SCAN_RESULTS.\n");
results->done = 1;
results->aborted = 0;
} // else probably an uninteresting multicast message.
return NL_SKIP;
}
static int callback_dump(struct nl_msg *msg, void *arg) {
// Called by the kernel with a dump of the successful scan's data. Called for each SSID.
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
char mac_addr[20];
struct nlattr *tb[NL80211_ATTR_MAX + 1];
struct nlattr *bss[NL80211_BSS_MAX + 1];
static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
[NL80211_BSS_TSF] = { .type = NLA_U64 },
[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
[NL80211_BSS_BSSID] = { },
[NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
[NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
[NL80211_BSS_INFORMATION_ELEMENTS] = { },
[NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
[NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
[NL80211_BSS_STATUS] = { .type = NLA_U32 },
[NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
[NL80211_BSS_BEACON_IES] = { },
};
// Parse and error check.
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
if (!tb[NL80211_ATTR_BSS]) {
printf("bss info missing!\n");
return NL_SKIP;
}
if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], bss_policy)) {
printf("failed to parse nested attributes!\n");
return NL_SKIP;
}
if (!bss[NL80211_BSS_BSSID]) return NL_SKIP;
if (!bss[NL80211_BSS_INFORMATION_ELEMENTS]) return NL_SKIP;
// Start printing.
mac_addr_n2a(mac_addr, nla_data(bss[NL80211_BSS_BSSID]));
printf("%s, ", mac_addr);
printf("%d MHz, ", nla_get_u32(bss[NL80211_BSS_FREQUENCY]));
print_ssid(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]), nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]));
printf("\n");
return NL_SKIP;
}
int do_scan_trigger(struct nl_sock *socket, int if_index, int driver_id) {
// Starts the scan and waits for it to finish. Does not return until the scan is done or has been aborted.
struct trigger_results results = { .done = 0, .aborted = 0 };
struct nl_msg *msg;
struct nl_cb *cb;
struct nl_msg *ssids_to_scan;
int err;
int ret;
int mcid = nl_get_multicast_id(socket, "nl80211", "scan");
nl_socket_add_membership(socket, mcid); // Without this, callback_trigger() won't be called.
// Allocate the messages and callback handler.
msg = nlmsg_alloc();
if (!msg) {
printf("ERROR: Failed to allocate netlink message for msg.\n");
return -ENOMEM;
}
ssids_to_scan = nlmsg_alloc();
if (!ssids_to_scan) {
printf("ERROR: Failed to allocate netlink message for ssids_to_scan.\n");
nlmsg_free(msg);
return -ENOMEM;
}
cb = nl_cb_alloc(NL_CB_DEFAULT);
if (!cb) {
printf("ERROR: Failed to allocate netlink callbacks.\n");
nlmsg_free(msg);
nlmsg_free(ssids_to_scan);
return -ENOMEM;
}
// Setup the messages and callback handler.
genlmsg_put(msg, 0, 0, driver_id, 0, 0, NL80211_CMD_TRIGGER_SCAN, 0); // Setup which command to run.
nla_put_u32(msg, NL80211_ATTR_IFINDEX, if_index); // Add message attribute, which interface to use.
nla_put(ssids_to_scan, 1, 0, ""); // Scan all SSIDs.
nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids_to_scan); // Add message attribute, which SSIDs to scan for.
nlmsg_free(ssids_to_scan); // Copied to `msg` above, no longer need this.
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, callback_trigger, &results); // Add the callback.
nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); // No sequence checking for multicast messages.
// Send NL80211_CMD_TRIGGER_SCAN to start the scan. The kernel may reply with NL80211_CMD_NEW_SCAN_RESULTS on
// success or NL80211_CMD_SCAN_ABORTED if another scan was started by another process.
err = 1;
ret = nl_send_auto(socket, msg); // Send the message.
printf("NL80211_CMD_TRIGGER_SCAN sent %d bytes to the kernel.\n", ret);
printf("Waiting for scan to complete...\n");
while (err > 0) ret = nl_recvmsgs(socket, cb); // First wait for ack_handler(). This helps with basic errors.
if (err < 0) {
printf("WARNING: err has a value of %d.\n", err);
}
if (ret < 0) {
printf("ERROR: nl_recvmsgs() returned %d (%s).\n", ret, nl_geterror(-ret));
return ret;
}
while (!results.done) nl_recvmsgs(socket, cb); // Now wait until the scan is done or aborted.
if (results.aborted) {
printf("ERROR: Kernel aborted scan.\n");
return 1;
}
printf("Scan is done.\n");
// Cleanup.
nlmsg_free(msg);
nl_cb_put(cb);
nl_socket_drop_membership(socket, mcid); // No longer need this.
return 0;
}
int main() {
int if_index = if_nametoindex("wlan0"); // Use this wireless interface for scanning.
// Open socket to kernel.
struct nl_sock *socket = nl_socket_alloc(); // Allocate new netlink socket in memory.
genl_connect(socket); // Create file descriptor and bind socket.
int driver_id = genl_ctrl_resolve(socket, "nl80211"); // Find the nl80211 driver ID.
// Issue NL80211_CMD_TRIGGER_SCAN to the kernel and wait for it to finish.
int err = do_scan_trigger(socket, if_index, driver_id);
if (err != 0) {
printf("do_scan_trigger() failed with %d.\n", err);
return err;
}
// Now get info for all SSIDs detected.
struct nl_msg *msg = nlmsg_alloc(); // Allocate a message.
genlmsg_put(msg, 0, 0, driver_id, 0, NLM_F_DUMP, NL80211_CMD_GET_SCAN, 0); // Setup which command to run.
nla_put_u32(msg, NL80211_ATTR_IFINDEX, if_index); // Add message attribute, which interface to use.
nl_socket_modify_cb(socket, NL_CB_VALID, NL_CB_CUSTOM, callback_dump, NULL); // Add the callback.
int ret = nl_send_auto(socket, msg); // Send the message.
printf("NL80211_CMD_GET_SCAN sent %d bytes to the kernel.\n", ret);
ret = nl_recvmsgs_default(socket); // Retrieve the kernel's answer. callback_dump() prints SSIDs to stdout.
nlmsg_free(msg);
if (ret < 0) {
printf("ERROR: nl_recvmsgs_default() returned %d (%s).\n", ret, nl_geterror(-ret));
return ret;
}
return 0;
}
nl80211.h only provides these enums for you to use with the real wireless library (which is libnl). You can use libnl by downloading it and including it in your c program: http://www.carisma.slowglass.com/~tgr/libnl/
Then with nl80211.h included, you can use all the enums that are defined with the commands defined in libnl.
code:
local void*
s_accept_connections(tmpsock)
void* tmpsock;
{
int32_t newfd;
int32_t tmp;
SOCKADDR_IN newsockaddr;
pthread_t id;
Connection* newconn;
const char *s;
char **splited;
int i;
StringVec *p;
StringVec* next;
Socket* sock;
tmp = sizeof(newsockaddr);
p = NULL;
next = NULL;
sock = (Socket *)tmpsock;
if (!sock)
return 0;
while (true){
newfd = accept(sock->fd,(SOCKADDR *)&newsockaddr,&tmp);
if (newfd <0){
if (check_error_async()){
pthread_mutex_lock(&g_socket_mutex);
#ifdef _WIN32
Sleep(1000);
#else
sleep(1);
#endif
pthread_mutex_unlock(&g_socket_mutex);
continue;
}
}else{
newconn = (Connection *)MyMalloc(sizeof(*newconn));
newconn->fd = newfd;
newconn->addr = newsockaddr;
s = (const char *)inet_ntoa(newsockaddr.sin_addr);
p = split_string(s,".");
if (p != NULL){
splited = (char **)MyMalloc(sizeof(*splited) + 12);
i = 0;
for (; p != NULL; p = next){
if (p && p->next){
next = p->next;
}else{ break; }
splited[i] = p->value;
i++;
}
newconn->ip = swap_uint32_t((uint32_t)(atoi(splited[0])) + (atoi(splited[1]) << 8) + (atoi(splited[2]) << 16) + (atoi(splited[3]) << 24));
MyFree((char *)splited);
}else{
newconn->ip = 0;
}
newconn->closed = false;
newconn->state = 0;
newconn->state |= S_NEED_LOGIN;
pthread_mutex_init(&g_ping_mutex,NULL);
pthread_cond_init(&g_ping_cond,NULL);
pthread_create(&id,NULL,s_ping_thread,(void *)newconn);
a_conn(&sock->conn,newconn);
#ifndef NDEBUG
_("Accepting connection...\n");
#endif
if (sock->has_callback){
sock->func(newconn);
#ifndef NDEBUG
_("Accepted connection\n");
#endif
}
}
}
return 0;
}
void
start_accept(sock,join)
Socket* sock;
bool join;
{
pthread_t id;
pthread_attr_t attr;
if (!sock)
return;
if (!sock->conn){
sock->conn = (Connection *)MyMalloc(sizeof(*sock->conn));
if (!sock->conn)
return;
}
set_nonblocking(sock->fd);
set_nonblocking(sock->conn->fd);
pthread_attr_init(&attr);
pthread_mutex_init(&g_socket_mutex,NULL);
if (join){
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
}else{
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
}
pthread_create(&id,&attr,s_accept_connections,sock);
if (join){
pthread_join(id,NULL);
pthread_attr_destroy(&attr);
pthread_mutex_destroy(&g_socket_mutex);
}
}
It simply gives 100% cpu, any ideas? if more code needed, ill post
What makes you believe that pthread_mutex_lock() is responsible for the CPU usage ?
Use a debugger to find out what is happening.
My guess is there is something wrong with your socket, making your accept() call non-blocking.
Check the return value/message (with perror() if you are running linux).
EDIT :
You need to know which piece of code is looping a debugger can help you to find this.
You have a while(true) loop that is very likely to be responsible for the enless loop and the 100% CPU usage. It should be ok since you have a call to accept() (here :newfd = accept(sock->fd,(SOCKADDR *)&newsockaddr,&tmp);) that is supposed to stop the thread/process until the next client connection. But if your socket is not correctly initialized accept() may return an error without waiting.