How to connect BLE devices using Linux bluetooth C library - c++

Description of the problem
I am trying to connect my Bluetooth devices with BLE to a Linux system using the Bluetooth C libraries (I am programming using C++), so here is the code I am currently using:
#include <string>
#include <iostream>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#define CONNECT_TIMEOUT 60 /* sec */
#define BLE_ERROR(e) std::cout << "Error: " << e << ": " << strerror(errno) << std::endl;
void connect(std::string addr){
uint16_t handle = 0;
uint8_t initiator_filter = 0;
uint8_t peer_type = LE_PUBLIC_ADDRESS;
uint8_t own_type = LE_PUBLIC_ADDRESS;
uint16_t interval = htobs(0x0005);
uint16_t window = htobs(0x0005);
uint16_t min_interval = 15;
uint16_t max_interval = 15;
uint16_t latency = 0;
uint16_t timeout = 0;
uint16_t min_ce_length = 1;
uint16_t max_ce_length = 1;
bdaddr_t bdaddr;
int r, dev_id, dd = -1;
dev_id = hci_get_route(NULL);
if (dev_id < 0)
{
BLE_ERROR("No local device");
goto finish;
}
dd = hci_open_dev(dev_id);
if (dd < 0)
{
BLE_ERROR("Cannot open socket");
goto finish;
}
r = str2ba(addr.c_str(), &bdaddr);
if(r < 0){
BLE_ERROR("Getting baddr");
goto finish;
}
r = hci_le_create_conn(dd,interval,window,initiator_filter,peer_type,
bdaddr,own_type,min_interval,max_interval,latency,timeout,min_ce_length,max_ce_length,
&handle,CONNECT_TIMEOUT * 1000000);
if(r < 0){
BLE_ERROR("Connecting device");
goto finish;
}
printf("\tHandle: %d (0x%04x)\n", handle, handle);
finish:
hci_close_dev(dd);
}
int main(){
connect(""); //TODO Complete with a functional MAC Address
return 0;
}
NOTE: You need to set a specific MAC in connect function parameter. I am also compiling with g++ using the following command:
/usr/bin/g++ -g /home/maria/projects/TestStackOverBLE/main.cpp -o /home/maria/projects/TestStackOverBLE/main -lbluetooth
Here are more information about my hci0 device using hciconfig -a command:
hci0: Type: Primary Bus: USB
BD Address: 24:4B:FE:3A:1A:B6 ACL MTU: 1021:6 SCO MTU: 255:12
UP RUNNING PSCAN
RX bytes:141559 acl:0 sco:0 events:5409 errors:0
TX bytes:59986 acl:0 sco:0 commands:2084 errors:0
Features: 0xff 0xff 0xff 0xfe 0xdb 0xfd 0x7b 0x87
Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3
Link policy: RSWITCH HOLD SNIFF PARK
Link mode: SLAVE ACCEPT
Name: 'maria'
Class: 0x3c010c
Service Classes: Rendering, Capturing, Object Transfer, Audio
Device Class: Computer, Laptop
HCI Version: (0xa) Revision: 0x999
LMP Version: (0xa) Subversion: 0x646b
Manufacturer: Realtek Semiconductor Corporation (93)
I am also using Ubuntu 18.04 with:
bluetoothctl v5.64
dbus v1.12.2-1ubuntu1
bluez v5.48-0ubuntu3.
And the result I am getting when I run the application is the following:
Error: Connecting device: Input/output error
Solution attempts
I first tried to document myself about how the bluetooth C libraries for Linux works (itis difficult to find any documentation and less for BLE), I need to connect using BLE since my device does not allow communication using Bluetooth classic and I cannot find the reason for the problem I am having. I also have tried to restart both the bluetooth service (using sudo service bluetooth restart) and the hci0 device (using sudo hciconfig hci0 reset) several times but none worked, I also tried restarting the PC and neither, I even tried the steps mentioned here that are quite similar to my case since previously the "Connection timeout" error has also happened to me but it didn't work either, it just returned the following code in case it was useful: Executing this command: hcitool cmd 0x08 0x000EI received the following output:
< HCI Command: ogf 0x08, ocf 0x000e, plen 0
> HCI Event: 0x0e plen 4
02 0E 20 0C
What can I do about this problem?
EDIT: I was researching and found that making dbus calls to the bluetooth service using C/C++ could work for me but it is quite difficult to find good documentation or concrete connection examples despite having reviewed lots of github projects as most of the code is too convoluted, included in many files and/or consecutive calls for what I am trying to find/understand

This is what the old hci_xxx bluetooth C functions are doing at the lowest level. They probably don't work now because bluez/dbus is getting in the way. The following code works on a Raspberry Pi because it disables bluez first, and could be the basis of a C program - but it would be much easier to use one of the github libraries mentioned in the comments.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
struct sockaddr_hci
{
unsigned short hci_family;
unsigned short hci_dev;
unsigned short hci_channel;
};
struct hci_filter
{
unsigned long type_mask;
unsigned long event_mask[2];
unsigned short opcode;
};
#define BTPROTO_HCI 1
#define SOL_HCI 0
#define HCI_FILTER 2
#define HCIDEVDOWN 0x400448CA
unsigned char eventmask[16] = { 1,1,0x0C,8,0xFF,0xFF,0xFB,0xFF,0x07,0xF8,0xBF,0x3D };
unsigned char lemask[16] = { 0x01,0x01,0x20,0x08,0xBF,0x05,0,0,0,0,0,0 };
unsigned char leopen[30] = {1,0x0D,0x20,0x19,0x60,0,0x60,0,0,0,0x66,0x55,0x44,0x33,0x22,0x11,0,0x18,0,0x28,0,0,0,0x11,0x01,0,0,0,0};
int main()
{
int n,len,dd;
struct sockaddr_hci sa;
struct hci_filter flt;
char buf[256];
// set board address 00:1E:C0:2D:17:7C
leopen[15] = 0x00;
leopen[14] = 0x1E;
leopen[13] = 0xC0;
leopen[12] = 0x2D;
leopen[11] = 0x17;
leopen[10] = 0x7C;
dd = socket(31, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, BTPROTO_HCI);
if(dd < 0)
{
printf("Socket open error\n");
return(0);
}
ioctl(dd,HCIDEVDOWN,0); // hci0
close(dd);
// AF_BLUETOOTH=31
dd = socket(31, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, BTPROTO_HCI);
if(dd < 0)
{
printf("Socket open error\n");
return(0);
}
sa.hci_family = 31; // AF_BLUETOOTH;
sa.hci_dev = 0; // hci0/1/2...
sa.hci_channel = 1; // HCI_CHANNEL_USER
if(bind(dd,(struct sockaddr *)&sa,sizeof(sa)) < 0)
{
printf("Bind failed\n");
close(dd);
return(0);
}
write(dd,eventmask,12);
write(dd,lemask,12);
printf("Send hci LE connect\n");
write(dd,leopen,29);
printf("If get reply = 04 3E 13 01 00.. then has connected OK\n");
printf("REPLY =");
for(n = 0 ; n < 10 ; ++ n)
{
len = read(dd,buf,sizeof(buf));
for(n = 0 ; n < len ; ++n)
printf(" %02X",buf[n]);
printf("\n");
sleep(1);
}
printf("\nExit and disconnect\n");
}

Related

poll() method not working in Linux but working in Mac

I am using C++ code snippet for port forwarding. The requirement is to do the hand shake between two ports. It should be two way communication. That is to forward what ever iscoming on the source port to destination port. And then to forward the response of the destination port to the source port.
This piece of code is working as expected on my mac system. But when I am running this code on Linux system I am facing one issue.
Issue:
The C++ code that I am using is having 3 parts:
establish_connection_to_source();
open_connection_to_destination();
processconnetion();
On Linux: establish_connection_to_source(); and open_connection_to_destination(); is working perfectly fine. But processconnetion(); is havng one issue.
Following is the process connection method:
void processconnetion()
{
buffer *todest = new buffer(socket_list[e_source].fd,socket_list[e_dest].fd);
buffer *tosrc = new buffer(socket_list[e_dest].fd,socket_list[e_source].fd);
if (todest == NULL || tosrc == NULL){
fprintf(stderr,"out of mememory\n");
exit(-1);
}
unsigned int loopcnt;
profilecommuncation srcprofile(COMM_BUFSIZE);
profilecommuncation destprofile(COMM_BUFSIZE);
while (true) {
int withevent = poll(socket_list, 2, -1);
loopcnt++;
fprintf(stderr,"loopcnt %d socketswith events = %d source:0x%x dest:0x%x\n", loopcnt, withevent, socket_list[e_source].revents, socket_list[e_dest].revents);
if ((socket_list[e_source].revents | socket_list[e_dest].revents) & (POLLHUP | POLLERR)) {
// one of the connections has a problem or has Hungup
fprintf(stderr,"socket_list[e_source].revents= 0x%X\n", socket_list[e_source].revents);
fprintf(stderr,"socket_list[e_dest].revents= 0x%X\n", socket_list[e_dest].revents);
fprintf(stderr,"POLLHUP= 0x%X\n", POLLHUP);
fprintf(stderr,"POLLERR= 0x%X\n", POLLERR);
int result;
socklen_t result_len = sizeof(result);
getsockopt(socket_list[e_dest].fd, SOL_SOCKET, SO_ERROR, &result, &result_len);
fprintf(stderr, "result = %d\n", result);
fprintf(stderr,"exiting as one connection had an issue\n");
break;
}
if (socket_list[e_source].revents & POLLIN) {
srcprofile.increment_size(todest->copydata());
}
if (socket_list[e_dest].revents & POLLIN) {
destprofile.increment_size(tosrc->copydata());
}
}
delete todest;
delete tosrc;
close(socket_list[e_source].fd);
close(socket_list[e_dest].fd);
srcprofile.dumpseensizes("source");
destprofile.dumpseensizes("destination");
}
Here it is giving error - exiting as one connection had an issue that means that if ((socket_list[e_source].revents | socket_list[e_dest].revents) & (POLLHUP | POLLERR)) is returning true. The issue is with the destination port and not in case of source.
Note:
Variales used in the processconnetion(); method:
socket_list is a structure of type pollfd. Following is the description:
struct pollfd {
int fd;
short events;
short revents;
};
pollfd socket_list[3];
#define e_source 0
#define e_dest 1
#define e_listen 2
Following is the output at the time for exit:
connecting to destination: destination IP / 32001.
connected...
loopcnt 1 socketswith events = 1 source:0x0 dest:0x10
socket_list[e_source].revents= 0x0
socket_list[e_dest].revents= 0x10
POLLHUP= 0x10
POLLERR= 0x8
result = 0
exiting as one connection had an issue
int withevent = poll(socket_list, 2, -1); here the withevent value returned is 1
Socket List Initialisation:
guard( (socket_list[e_listen].fd = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP )), "Failed to create socket listen, error: %s\n", "created listen socket");
void guard(int n, char *msg, char *success)
{
if (n < 0) {
fprintf(stderr, msg, strerror(errno) );
exit(-1);
}
fprintf(stderr,"n = %d %s\n",n, success);
}
I am not able to figure out the issue as it is working fine in mac. Any leads why this behaviour in Linux is highly appreciated. Thanks in advance.

Adafruit Fona establishes connection with echo server, but doesn't send over any data

Using mbed OS and stm32 nucleo board with Adafruit Fona 3g, I am trying to send data to a server via 3g connection. I am using the .cpp file and .h file posted here: https://os.mbed.com/users/Nels885/code/Adafruit_FONA_3G/file/b18cfba4283a/
The code seems to get stuck on getTCPtimeout. I am having trouble figuring out why this is the case.
I have tried commenting out the getTCPtimeout function to see the results and the code runs through completely, but never establishes a connection with the server.
#include "mbed.h"
#include "Adafruit_FONA.h"
#define FONA_RST D4
#define FONA_TX D1
#define FONA_RX D0
#define FONA_RI D7 //not used
char replybuffer[255];
Adafruit_FONA_3G fona(FONA_TX, FONA_RX, FONA_RST, FONA_RI);
Serial pc(USBTX, USBRX);
int main()
{
fona.TCPinitialize();
pc.printf ("initialize \n");
char *Timeout = "10000000";
fona.getTCPtimeout(Timeout);
pc.printf ("timeout \n");
char * Server = "47.218.188.133";
uint16_t Port = 23;
fona.TCPconnect(Server,Port);
pc.printf ("connect \n");
char * Packet = "Pick Up %";
fona.TCPsend(Packet);
pc.printf ("send \n");
fona.TCPclose();
pc.printf ("close \n");
}
Edit: I was running the code and noticed that after fixing the above issue, the code would get stuck TCPSend function, specifically right before
packet[0] = 0;
which is shown down here:
bool Adafruit_FONA_3G::TCPsend(char *packet)
{
if (strlen(packet) > 0) {
mySerial.printf("%s", packet);
//mySerial.printf("%s\r\n", packet);
readline();
packet[0] = 0;
return true;
} else return false;
}
When commenting out the line, the code would run all the way through. I am still in the process of testing to see if the code still functions as intended, but my question is what exactly is the purpose of packet[0] = 0;?
Adafruit_FONA_3G::getTCPtimeout() assumes that you pass it a writable buffer of size > 20. You're passing a read-only buffer of smaller size. So, replace
char *Timeout = "10000000";
with
char Timeout[21];

Why are Go sockets slower than C++ sockets? [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 years ago.
Improve this question
I benchmarked a simple socket ping pong test in Go and C++. The client begins by sending 0 to the server. The server increments whatever number it gets and sends it back to the client. The client echos the number back to the server, and stops once the number is 1,000,000.
Both the client and the server are on the same computer, so I use a Unix socket in both cases. (I also tried same-host TCP sockets, which showed a similar result).
The Go test takes 14 seconds, whereas the C++ test takes 8 seconds. This is surprising to me because I have run a fair number of Go vs. C++ benchmarks, and generally Go is as performant as C++ as long as I don't trigger the garbage collector.
I am on a Mac, though commenters have also reported that the Go version is slower on Linux.
Wondering if I am missing a way to optimize the Go program or if there are just inefficiencies under the hood.
Below are the commands I run to carry out the test, along with the test results. All code files are pasted at the bottom of this question.
Run Go server:
$ rm /tmp/go.sock
$ go run socketUnixServer.go
Run Go client:
$ go build socketUnixClient.go; time ./socketUnixClient
real 0m14.101s
user 0m5.242s
sys 0m7.883s
Run C++ server:
$ rm /tmp/cpp.sock
$ clang++ -std=c++11 tcpServerIncUnix.cpp -O3; ./a.out
Run C++ client:
$ clang++ -std=c++11 tcpClientIncUnix.cpp -O3; time ./a.out
real 0m8.690s
user 0m0.835s
sys 0m3.800s
Code files
Go server:
// socketUnixServer.go
package main
import (
"log"
"net"
"encoding/binary"
)
func main() {
ln, err := net.Listen("unix", "/tmp/go.sock")
if err != nil {
log.Fatal("Listen error: ", err)
}
c, err := ln.Accept()
if err != nil {
panic(err)
}
log.Println("Connected with client!")
readbuf := make([]byte, 4)
writebuf := make([]byte, 4)
for {
c.Read(readbuf)
clientNum := binary.BigEndian.Uint32(readbuf)
binary.BigEndian.PutUint32(writebuf, clientNum+1)
c.Write(writebuf)
}
}
Go client:
// socketUnixClient.go
package main
import (
"log"
"net"
"encoding/binary"
)
const N = 1000000
func main() {
c, err := net.Dial("unix", "/tmp/go.sock")
if err != nil {
log.Fatal("Dial error", err)
}
defer c.Close()
readbuf := make([]byte, 4)
writebuf := make([]byte, 4)
var currNumber uint32 = 0
for currNumber < N {
binary.BigEndian.PutUint32(writebuf, currNumber)
c.Write(writebuf)
// Read the incremented number from server
c.Read(readbuf[:])
currNumber = binary.BigEndian.Uint32(readbuf)
}
}
C++ server:
// tcpServerIncUnix.cpp
// Server side C/C++ program to demonstrate Socket programming
// #include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <string.h>
#include <unistd.h>
// Big Endian (network order)
unsigned int fromBytes(unsigned char b[4]) {
return b[3] | b[2]<<8 | b[1]<<16 | b[0]<<24;
}
void toBytes(unsigned int x, unsigned char (&b)[4]) {
b[3] = x;
b[2] = x>>8;
b[1] = x>>16;
b[0] = x>>24;
}
int main(int argc, char const *argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_un saddr;
int saddrlen = sizeof(saddr);
unsigned char recv_buffer[4] = {0};
unsigned char send_buffer[4] = {0};
server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
saddr.sun_family = AF_UNIX;
strncpy(saddr.sun_path, "/tmp/cpp.sock", sizeof(saddr.sun_path));
saddr.sun_path[sizeof(saddr.sun_path)-1] = '\0';
bind(server_fd, (struct sockaddr *)&saddr, sizeof(saddr));
listen(server_fd, 3);
// Accept one client connection
new_socket = accept(server_fd, (struct sockaddr *)&saddr, (socklen_t*)&saddrlen);
printf("Connected with client!\n");
// Note: if /tmp/cpp.sock already exists, you'll get the Connected with client!
// message before running the client. Delete this file first.
unsigned int x = 0;
while (true) {
valread = read(new_socket, recv_buffer, 4);
x = fromBytes(recv_buffer);
toBytes(x+1, send_buffer);
write(new_socket, send_buffer, 4);
}
}
C++ client:
// tcpClientIncUnix.cpp
// Server side C/C++ program to demonstrate Socket programming
// #include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <string.h>
#include <unistd.h>
// Big Endian (network order)
unsigned int fromBytes(unsigned char b[4]) {
return b[3] | b[2]<<8 | b[1]<<16 | b[0]<<24;
}
void toBytes(unsigned int x, unsigned char (&b)[4]) {
b[3] = x;
b[2] = x>>8;
b[1] = x>>16;
b[0] = x>>24;
}
int main(int argc, char const *argv[])
{
int sock, valread;
struct sockaddr_un saddr;
int opt = 1;
int saddrlen = sizeof(saddr);
// We'll be passing uint32's back and forth
unsigned char recv_buffer[4] = {0};
unsigned char send_buffer[4] = {0};
sock = socket(AF_UNIX, SOCK_STREAM, 0);
saddr.sun_family = AF_UNIX;
strncpy(saddr.sun_path, "/tmp/cpp.sock", sizeof(saddr.sun_path));
saddr.sun_path[sizeof(saddr.sun_path)-1] = '\0';
// Accept one client connection
if (connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) != 0) {
throw("connect failed");
}
int n = 1000000;
unsigned int currNumber = 0;
while (currNumber < n) {
toBytes(currNumber, send_buffer);
write(sock, send_buffer, 4);
// Read the incremented number from server
valread = read(sock, recv_buffer, 4);
currNumber = fromBytes(recv_buffer);
}
}
First of all, I confirm that the Go programs from this question do run noticeably slower than the C++ ones. I think that it's indeed interesting to know why.
I profiled the Go client and server with the pprof and found out that syscall.Syscall takes 70% of the total execution time. According to this ticket, in Go syscalls are approximately 1.4 times slower than in C.
(pprof) top -cum
Showing nodes accounting for 18.78s, 67.97% of 27.63s total
Dropped 44 nodes (cum <= 0.14s)
Showing top 10 nodes out of 44
flat flat% sum% cum cum%
0.11s 0.4% 0.4% 22.65s 81.98% main.main
0 0% 0.4% 22.65s 81.98% runtime.main
18.14s 65.65% 66.05% 19.91s 72.06% syscall.Syscall
0.03s 0.11% 66.16% 12.91s 46.72% net.(*conn).Read
0.10s 0.36% 66.52% 12.88s 46.62% net.(*netFD).Read
0.16s 0.58% 67.10% 12.78s 46.25% internal/poll.(*FD).Read
0.06s 0.22% 67.32% 11.87s 42.96% syscall.Read
0.11s 0.4% 67.72% 11.81s 42.74% syscall.read
0.02s 0.072% 67.79% 9.30s 33.66% net.(*conn).Write
0.05s 0.18% 67.97% 9.28s 33.59% net.(*netFD).Write
I gradually decreased the number of Conn.Write and Conn.Read calls and increased the size of the buffer accordingly, so that the number of transferred bytes stayed the same. The result is that the fewer these calls the program makes, the closer its performance to the C++ version.

LibUSB C++ Format of USB transfer differs

I've been using stack overflow for a long time now, and most of the problems a solution is already available. It is the first time that I actually couldn't figure it out with the web. I hope someone has the answer to the following problem.
Introduction
I am currently working on a project which should be capable of executing a command and act upon its response. This project runs on a debian based system in a c++ console application. In order to be able to perform such commands I tried using the LibUSB library.
The problem
Whenever packets are being sent it does not return a valid response as described in the documentation of the hardware. a default tool is available which triggers a callibration command, I sniffed these packets with Wireshark, but the structure of the OUT interrupt calls of the callibration tool differs from the LibUSB generated one, thus (I think) causing the command to not be executed.
The documentation provides one of the following commands, which should run a diagnostics check that returns 5 bytes of data.
[0] Header: 0x02
[1] Command: 0x4C
[2] Byte to send: 0x02 (N bytes to send, Argument + data size)
[3] Argument: 0x09
[4] Data: 0x00
The response should have the following format:
[0] Header: 0x02
[1] Command: 0x4C
[2] Byte to send: 0x03 (N bytes to send, Argument + data size)
[3] Argument: 0x09
[4] Processing result: D-1
[5] Diagnostic result: D-2
D-1: either 0x01: Normal or 0x00 Error D-2: either 0x00: Normal or not 0x00, linked error code.
Things tried so far
Transfer types:
Synchronous:
Libusb_bulk_transfer
Libusb_control_transfer
libusb_interrupt_transfer
Asynchronous:
Libusb_fill_bulk_transfer
Libusb_fill_control_transfer
Libusb_fill_interrupt_transfer
I tried both async as synchronous implementations for the LibUSB library. The control transfer I tried randomly switching the variables after the most logical ways of filling them had ran out, without success, as to be expected. Since the results found in the packet sniffing clearly indicated INTERRUPT calls being made.
Interfaces: The hardware has two interfaces. Interface 0 which contains OUT 0x02 and IN 0x81, and interface 1 which contains OUT 0x04 and IN 0x83. The sniffing of the USB interrupt call to the device triggered by the tooling provided that interface 1 is being used for the diagnostics command. (Also tried interface 0 with both IN and OUT, couldn't get it to work.
Packet sniffing with Wireshark
Results of the packet sniffing
Request and response generated with the tooling: IMG: Interrupt OUT (I marked the bit where to command is actually provided) IMG: Interrupt IN response This code actually works and returns the, expected, dataset in its data slot. (as described above, the return format is correct, 0x01 and 0x00).
Request and response generated with the LibUSB using code: IMG: Interrupt OUT IMG: Interrupt IN response
Yes, I also tried setting the buffer to a size of 64, the max buffer size for the hardware. Sadly didn't work. As seen clearly, both requests differ a lot, do I use the wrong transfer method? Is it another supported format in which you can send commands?
Used Code snippet:
The code snippet is a bit outdated, I tried re-writing / editing it several times, the last implementations being used from online examples.
#define USB_VENDOR_ID <VENDOR_ID>/* USB vendor ID used by the device
* 0x0483 is STMs ID
*/
#define USB_PRODUCT_ID <PRODUCT_ID> /* USB product ID used by the device */
#define USB_ENDPOINT_IN (LIBUSB_ENDPOINT_IN | 0x83) /* endpoint address */
#define USB_ENDPOINT_OUT (LIBUSB_ENDPOINT_OUT | 0x04) /* endpoint address */
#define USB_TIMEOUT 3000 /* Connection timeout (in ms) */
#define INTERFACE_NO 1
static libusb_context *ctx = NULL;
static libusb_device_handle *handle;
static uint8_t receiveBuf[64];
uint8_t transferBuf[64];
uint16_t counter=0;
int main(int argc, char **argv) {
libusb_device **devs; //pointer to pointer of device, used to retrieve a list of devices
libusb_device_handle *dev_handle; //a device handle
libusb_context *ctx = NULL; //a libusb session
int r; //for return values
ssize_t cnt; //holding number of devices in list
r = libusb_init(&ctx); //initialize the library for the session we just declared
if(r < 0) {
qDebug()<<"Init Error "<<r<<endl; //there was an error
return 1;
}
libusb_set_debug(ctx, 4); //set verbosity level to 3, as suggested in the documentation
cnt = libusb_get_device_list(ctx, &devs); //get the list of devices
if(cnt < 0) {
qDebug()<<"Get Device Error"<<endl; //there was an error
return 1;
}
qDebug()<<cnt<<" Devices in list."<<endl;
dev_handle = libusb_open_device_with_vid_pid(ctx, 0x0AFA, 0x7D3); //these are vendorID and productID I found for my usb device
if(dev_handle == NULL)
qDebug()<<"Cannot open device"<<endl;
else
qDebug()<<"Device Opened"<<endl;
libusb_free_device_list(devs, 1); //free the list, unref the devices in it
unsigned char *data = new unsigned char[5] { 0x02, 0x4C, 0x02, 0x09, 0 }; //data to write
data[0]= 0x02;data[1]= 0x4C;data[2]=0x02;data[3]=0x09; data[4]= 0; //some dummy values
int actual; //used to find out how many bytes were written
if(libusb_kernel_driver_active(dev_handle, INTERFACE_NO) == 1) { //find out if kernel driver is attached
qDebug()<<"Kernel Driver Active"<<endl;
if(libusb_detach_kernel_driver(dev_handle, INTERFACE_NO) == 0) //detach it
qDebug()<<"Kernel Driver Detached!"<<endl;
}
r = libusb_claim_interface(dev_handle, INTERFACE_NO); //claim interface 0 (the first) of device (mine had jsut 1)
if(r < 0) {
qDebug()<<"Cannot Claim Interface"<<endl;
return 1;
}
qDebug()<<"Claimed Interface"<<endl;
for(int i = 0; i != sizeof(data); i++) {
fprintf(stderr, "[%d] - %02x\n", i, data[i]);
}
qDebug()<<"Writing Data..."<<endl;
r = libusb_bulk_transfer(dev_handle, (USB_ENDPOINT_OUT | LIBUSB_ENDPOINT_OUT), data, sizeof(data), &actual, 0); //my device's out endpoint was 2, found with trial- the device had 2 endpoints: 2 and 129
if(r == 0 && actual == sizeof(data)) //we wrote the 4 bytes successfully
qDebug()<<"Writing Successful!"<<endl;
else
qDebug()<<"Write Error"<<endl;
fprintf(stderr, "Error Writing: %s", libusb_strerror(static_cast<libusb_error>(r)));
r = libusb_release_interface(dev_handle, INTERFACE_NO); //release the claimed interface
if(r!=0) {
qDebug()<<"Cannot Release Interface"<<endl;
return 1;
}
qDebug()<<"Released Interface"<<endl;
libusb_close(dev_handle); //close the device we opened
libusb_exit(ctx); //needs to be called to end the
delete[] data; //delete the allocated memory for data
return 0;
}
I hope I that there's someone out there capable and willing to help me out here, because I've been working on this for three days straight and still haven't gotten a logical solution to this problem.
Thanks in advance!
~ Mark
Thanks for your response! I currently found a solution to the problem! It had nothing to do with using both C / C++. Sorry for the code being a bit messy. I wrote it several times so tidiness wasn't my priority, though I will keep it in mind for a possible future post on StackOverflow. Even though solved I added results of sniffing both packets going IN and OUT, hoping it may help others with a possible same issue.
Well, what was the problem?
So, the capture of the tool indicated the last 64 bit being the payload of the request and its data, this is for both OUT and IN. (As to be seen in the images now actually provided) and as I said before, I tried allocating arrays with a size of 64 and setting the first few slots with the data necessary for the operation. As for the other slots, they were filled with the leftovers sitting at those allocated memory addresses.
What did I do to fix it
So, what I did was the following. After initializing an array and assigning it a size of 64 I set all of the allocated slots to 0 with the memset command, so the array would be completely cleared of left-over data. This left me with a clean array in which I could set the variables necessary for the command I wanted to send. (See the following snippet)
// Initialize array of 64 bytes.
uint8_t *data = new uint8_t[64];
memset(data, 0x00, 64);
data[0] = 0x02; data[1] = 0x4C; data[2] = 0x01; data[3] = 0x17;
I tidied up the code a bit to provide better readability, here is the code I used which works! Hopefully others find this information useful.
//*** DEPENDENCIES *************************************************************
// QT
#include <QCoreApplication>
#include <QtCore/QDebug>
// Others
#include <libusb.h>
#include <iostream>
//*** VARIABLES ****************************************************************
#define USB_VENDOR_ID <VENDOR_ID_GOES_HERE>
#define USB_PRODUCT_ID <PRODUCT_ID_GOES_HERE>
#define USB_ENDPOINT_OUT 0x04
#define USB_ENDPOINT_IN 0x83
#define INTERFACE_NO 0x01
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
libusb_device *dev;
libusb_device_handle *dev_handle;
libusb_context *ctx = NULL;
//*** INITIALIZATION *******************************************************
uint r = libusb_init(&ctx);
// Check if initiated succesfully
if ( r < 0 ) { qDebug() << "Init error."; return 1; }
libusb_set_debug(ctx, 4);
dev_handle = libusb_open_device_with_vid_pid(ctx, USB_VENDOR_ID, USB_PRODUCT_ID);
if (dev_handle == NULL) { qDebug() << "Could not open device."; return 1;}
qDebug() << "Device opened succesfully!";
// Check if kernel driver, detach
if(libusb_kernel_driver_active(dev_handle, INTERFACE_NO) == 1) {
qDebug() << "Kernel Driver Active";
if(libusb_detach_kernel_driver(dev_handle, INTERFACE_NO) == 0) {
qDebug() << "Kernel Driver Detached";
}
}
// Claim interface
r = libusb_claim_interface(dev_handle, INTERFACE_NO);
if ( r < 0 ) {
qDebug() << "Could not claim interface.";
return 1;
}
qDebug() << "Interface claimed.";
//*** EXECUTION OF USB TRANSFERS *******************************************
// Prepare command
int actual_written;
// Initialize array of 64 bytes.
uint8_t *data = new uint8_t[64];
memset(data, 0x00, 64);
data[0] = 0x02; data[1] = 0x4C; data[2] = 0x01; data[3] = 0x17;
qDebug() << "================= OUT ==============================";
//*** ATTEMPT TO WRITE COMMAND *********************************************
r = libusb_bulk_transfer(dev_handle,
USB_ENDPOINT_OUT,
data, 64,
&actual_written,
10000);
qDebug() << "OUT status: " << libusb_strerror(static_cast<libusb_error>(r));
if (r == 0 && actual_written == 64) {
qDebug() << "Succesfully written!";
} else {
qDebug() << "||" << r << "||"<< actual_written << "||"
<< "Could not write.";
}
qDebug() << "================== IN ===============================";
//*** ATTEMPT TO READ FEEDBACK *********************************************
// Initialize array of 64 bytes.
uint8_t *feedback = new uint8_t[64];
memset(feedback, 0x00, 64);
int actual_received;
r = libusb_bulk_transfer(
dev_handle,
USB_ENDPOINT_IN,
feedback,
64,
&actual_received,
0);
qDebug() << "IN status: " << libusb_strerror(static_cast<libusb_error>(r));
if(r == 0 && actual_received == 64) {
qDebug("\nRetrieval successful!");
qDebug("\nSent %d bytes with string: %s\n", actual_received, feedback);
} else {
qDebug() << actual_received << "||" <<feedback << "||"
<< "Could not read incoming data. ||";
}
for( int m = 0; m < 64; m++)
{
fprintf(stderr, "[%d] - %02x\n", m, feedback[m]);
}
if (feedback[4] != 0x01) {
qDebug() << "Unsuccesful offset adjustment.";
return -1;
}
// Further code should go here.
//*** FREEING USB **********************************************************
// Releasing interface
r = libusb_release_interface(dev_handle, INTERFACE_NO);
if ( r < 0 ) { qDebug() << "Could not release interface."; return 1; }
qDebug() << "Interface released.";
libusb_close(dev_handle);
libusb_exit(ctx);
delete[] data;
delete[] feedback;
qDebug() << "End of main";
return 0;
}
Thomas and David, thanks a lot!
~ Mark

how to get Ethernet adapter name from IP in c in centos

have two ethernet adapters, so i have two different ip addresses. Now I ant to find the name of the adapter with the respective ip. Like, I have intel card with ip 192.168.10.1. How to retrieve this adapter name in centos(linux) using C or C++ without any third party installation?
I need to find the manufacturer name( not eth0,etc..). This manufacturer list is in "/usr/share/hwdata/pci.ids", but i'm unable to map that name with the ip address. I could get the list of adapter name using 'lscpu | grep "Ethernet"'. But again the question arises to mapping the names with ip address.
There is getifaddrs function in standard libc. I modified an example from manual page.
You can't get names from the kernel, but it provides PCI IDs in /sys file systems. You can use libpci to resolve these numbers into filenames. Current code doesn't support USB devices and subdevice numbers.
#define _GNU_SOURCE /* To get defns of NI_MAXSERV and NI_MAXHOST */
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/if_link.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <pci/pci.h>
/* PCI IDs are contained in /sys filesystem. */
unsigned long read_sysfs_uint(const char* ifa_name, const char* info) {
char path[PATH_MAX];
char buf[12];
int fd;
snprintf(path, PATH_MAX, "/sys/class/net/%s/device/%s", ifa_name, info);
fd = open(path, O_RDONLY);
if(fd == -1)
return 0;
if(read(fd, buf, 12) == -1) {
close(fd);
return 0;
}
close(fd);
return strtoul(buf, NULL, 16);
}
/* Try to get PCI IDs and get PCI device name for it.
XXX: doesn't check for subsystem's numbers */
void print_pci_ids(const char* ifa_name) {
int vendor = (int) read_sysfs_uint(ifa_name, "vendor");
int device = (int) read_sysfs_uint(ifa_name, "device");
int subsystem_vendor = (int) read_sysfs_uint(ifa_name, "subsystem_vendor");
int subsystem_device = (int) read_sysfs_uint(ifa_name, "subsystem_device");
struct pci_access *pacc = pci_alloc();
char namebuf[256];
printf("PCI IDs: %x %x %x %x\n", vendor, device, subsystem_device, subsystem_vendor);
pci_init(pacc);
if(pci_lookup_name(pacc, namebuf, 256,
PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
vendor, device)) {
printf("PCI Name: %s\n", namebuf);
}
pci_cleanup(pacc);
}
int main(int argc, char *argv[])
{
struct ifaddrs *ifaddr, *ifa;
struct in_addr* ifa_inaddr;
struct in_addr addr;
int family, s, n;
if(argc != 2) {
fprintf(stderr, "Usage: getifaddr <IP>\n");
return EXIT_FAILURE;
}
if (inet_aton(argv[1], &addr) == 0) {
perror("inet_aton");
return EXIT_FAILURE;
}
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs");
return EXIT_FAILURE;
}
/* Walk through linked list, maintaining head pointer so we
can free list later */
for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
if (ifa->ifa_addr == NULL)
continue;
/* We seek only for IPv4 addresses */
if(ifa->ifa_addr->sa_family != AF_INET)
continue;
ifa_inaddr = &(((struct sockaddr_in*) ifa->ifa_addr)->sin_addr);
if(memcmp(ifa_inaddr, &addr, sizeof(struct in_addr)) == 0) {
printf("Interface: %s\n", ifa->ifa_name);
print_pci_ids(ifa->ifa_name);
}
}
freeifaddrs(ifaddr);
return EXIT_SUCCESS;
}
Compile it with libpci (you'll need to install corresponding devel package):
$ gcc getifname.c -lpci -o ./getifname
Here are examples of its usage:
$ ./getifname
Usage: getifaddr <IP>
$ ./getifname dlks
inet_aton: Success
$ ./getifname 127.0.0.1
Interface: lo
PCI IDs: 0 0 0 0
PCI Name: Device 0000:0000
$ ./getifname 192.168.13.144
Interface: wlan0
PCI IDs: 8086 88e 4060 8086
PCI Name: Intel Corporation Centrino Advanced-N 6235
Im assuming by adapter name you mean eth0/eth1/etc. and not Manufacturer/Model. If so, one possible solution (a little convoluted but it works) would be to perform an ifconfig sys call and pipe it to a text file. From there you can perform a search of the text file to look for the IP address and then from there since the output is constant you can just use the starting location of the IP as the basis of getting to the adapter name.
That is actually somewhat tricky since linux does not have a common, generic driver stack API like windows - basically it boils down to 3 options :
read the special files which are exported by the kernel : https://stackoverflow.com/a/5611176/351861
call lspci and parse its output : http://prefetch.net/articles/linuxpci.html
copy the functionality of lspci and actually write your own app, as you can see you will need several kernel data structures like pcimap_entry and whatnot, but it should be straighforward since you can literally syphon the knowledge of ye olde kernel grandmasters : https://github.com/gittup/pciutils/blob/gittup/ls-kernel.c