I'm writing a Memcached UDP client with libmemcached/memcached.h to send some arbitrary loads on Memcached server. I can send set requests in UDP but I'm unable to send get requests, here is the snippet I wrote for this!
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <libmemcached/memcached.h>
#include <time.h>
#include <assert.h>
#include <stdlib.h>
#include <math.h>
#include <signal.h>
int main(int argc, char *argv[])
{
memcached_server_st *servers = NULL;
memcached_st *memc;
memcached_return rc;
char * res;
char *key= "kay";
int size = 1000;
char * value = malloc(size);
uint32_t flags;
size_t return_value_length;
char * ip = argv[2];
memset(value, 1, size);
memc = memcached_create(NULL);
servers= memcached_server_list_append(servers, ip, 11211, &rc);
rc = memcached_server_push(memc, servers);
memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, (uint64_t)1);
rc = memcached_set(memc, key, strlen(key), value, strlen(value), (time_t)0, (uint32_t)0);
if (rc == MEMCACHED_SUCCESS)
fprintf(stderr,"Key stored successfully\n");
else
fprintf(stderr,"Couldn't store key: %s\n",memcached_strerror(memc, rc));
while ( true)
{
res = memcached_get(memc, key, strlen(key), &return_value_length, &flags, &rc);
free(res);
if(rc != MEMCACHED_SUCCESS)
{
fprintf(stderr, "%s\n", memcached_strerror(memc, rc));
}
}
memcached_free(memc);
return 0;
Actually, get requests always are unsuccessful!!! I also monitored the packets with Wireshark the client doesn't even send any packet out to the server!!! And it just got failed while sending get request.
Is there any obvious problem in the code which I couldn't see?
Thank you
According to the manpage of memcached_behaviour_set():
The following operations will return MEMCACHED_NOT_SUPPORTED when
executed with the MEMCACHED_BEHAVIOR_USE_UDP enabled:
memcached_version(), memcached_stat(), memcached_get(),
memcached_get_by_key(), memcached_mget(), memcached_mget_by_key(),
memcached_fetch(), memcached_fetch_result(),
memcached_fetch_execute().
So indeed, memcached_get() does not work when the memcached-handle is set to UDP transport. You will have to use TCP for that.
Related
Warning: I'm quite new to C and memory mgmt and all that stuff (coming from interpreted/JITed languages).
So I'm making a little library for creating TCP servers easily (as an exercise in network programming). An example of usage could look like the following:
#include <stdio.h>
#include "ohsimpletcp.h"
void echo(int socket_fd) {
char *message = malloc(100 * sizeof(char));
while (ost_receive(socket_fd, message, 100) > 0) {
ost_send(socket_fd, message);
}
}
int main() {
if (ost_serve(1337, echo) == -1) {
perror("An error occurred");
return 1;
}
return 0;
}
But my question is, for making this thing smoothly concurrent for a high number of clients, do I need to create a new process for every connected client in the backend? Or could I solve this with select() somehow?
ohsimpletcp.h:
#ifndef REG4IN_OST_H
#define REG4IN_OST_H 1
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
int ost_serve(int port, void (*handler)(int socket_fd));
int ost_send(int socket_fd, char *message);
int ost_receive(int socket_fd, char *message, int length);
#endif
Working on a program that is meant to emulate data layers in networking. I've got messages coming through to the server correctly, however, the client is not receiving the ACK frame from the server. This is causing my program to wait endlessly. Any help in fixing the matter is appreciated.
Sender
#include <stdio.h>
#include <unistd.h>
#define MAXFRAME 97
main(int argc, char* argv[]){
char *frame;
int len = 0;
int c;
dlinits("spirit.cba.csuohio.edu", 43525);
frame = malloc(MAXFRAME);
FILE *file = fopen(argv[1], "r");
if (file == NULL)
return NULL;
while ((c = fgetc(file)) != EOF)
{
if(len == (MAXFRAME-1)){
dlsend(frame, len, 0);
len = 0;
memset(frame,0,strlen(frame));
}
frame[len++] = (char) c;
}
dlsend(frame, len, 1);
}
Receiver
#include <string.h>
#include <unistd.h>
char* dlrecv();
main(){
char* test[100];
dlinitr(43525);
while(1){
strcpy(test,dlrecv());
printf("%s\n", test);
}
}
Data Layer
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define BUFMAX 100
static int sk;
static struct sockaddr_in remote;
static struct sockaddr_in local;
static int fnum = 0;
static expFra = 0x00;
dlinits(char* host, int port){//initialize sender
struct hostent *hp;
sk = socket(AF_INET, SOCK_DGRAM, 0);
remote.sin_family = AF_INET;
hp = gethostbyname(host);
if (hp == NULL){
printf("Can't find host name\n");
exit(1);
}
bcopy(hp->h_addr,&remote.sin_addr.s_addr,hp->h_length);
remote.sin_port = ntohs(port);
}
dlinitr(int port){//initialize receiver
int rlen = sizeof(remote);
int len = sizeof(local);
char buf[BUFMAX];
sk = socket(AF_INET,SOCK_DGRAM,0);
local.sin_family = AF_INET;
local.sin_addr.s_addr = INADDR_ANY;
local.sin_port = htons(port);
bind (sk, &local,sizeof(local));
getsockname(sk,&local,&len);
}
dlsend(char* msg, int len, int end){//send data
int header = 0x00;
int result;
char *ackframe = malloc(3);
unsigned char *nmsg;
nmsg = malloc(100);
if ((fnum%2) == 1){
header = header|0x02;
}
if (end == 1){
header = header|0x40;
}
header = header^0xff;
printf("%x\n %x\n", header, 0);
nmsg[0] = (char)header;
len++;
printf("%s\n", nmsg);
memcpy(nmsg + 1, msg, strlen(msg));
result = crc(nmsg, len);
nmsg[len++] = ((result >> 8) & 0xff);
nmsg[len++] = (result & 0xff);
printf("%s\n", nmsg);
sendto(sk,nmsg,len,0,&remote,sizeof(remote));
read(sk,ackframe,3);
printf("Ack Received: %s\n", ackframe);
fnum++;
}
char* dlrecv(){//receive data
int result;
int header;
int ACK = 1;
char alen = 1;
char *ackframe = malloc(3);
unsigned char* msg = malloc(100);
while (ACK){
recvfrom(sk,msg,BUFMAX,0,&remote,sizeof(remote));
int len = strlen(msg);
result = crc(msg, len);
if (result == 0){
msg[--len] = 0;
msg[--len] = 0;
header = msg[0];
printf("Header %x expFra %x\n", header, expFra);
header = header^0xff;
printf("Header %x expFra %x\n", header, expFra);
if ((header<<4) == (expFra<<4)){
expFra = expFra^0x02;
ackframe[0] = (0x10|header);
result = crc(ackframe, alen);
ackframe[alen++] = ((result >> 8) & 0xff);
ackframe[alen++] = (result & 0xff);
sendto(sk,ackframe,strlen(ackframe),0,&remote,sizeof(remote));
printf("Ack Sent: %s\n", ackframe);
ACK = 0;
}
}
}
printf("%s\n", msg);
return ++msg;
}
EDIT for the moment these are working on the same machine.
EDIT I ran a check using errno, which returned error 22 for the sendto inside of dlrecv.
My experience with UDP has been that read() (which you're using at the end of your dlsend()) is very hit-or-miss, especially when paired with sendto(). Unless there's a good reason not to do it, changing read() to recvfrom() should fix the problem.
Your code also throws a lot of warnings for mismatched types. They're kinda-sorta harmless, but make tracking anything else down more complicated.
After that, the final acknowledgment-sendto() is using bad socket data. Poking around, the reason is that you're passing an integer in (sizeof(remote)) as a pointer to the address's size in the previous recvfrom() call. If the initial size given is too small, recvfrom() produces unreliable results. If it needs less space than that, it'll change that value to tell you what it used.
So, you need to declare a integer initialized to the size of a sockaddr_in structure, and pass a pointer to it as that last parameter. With those changes, assuming the server arrives at the sendto() function (your sample only has it under a single conditional branch), you'll get the right values for the address and will be able to send the acknowledgment.
The big lessons learned should be (a) make sure all the types are correct and review every warning and (b) check the return value of every socket call and print the error if you get a -1 back.
I'm trying to transfer a file from a server to a client using TCP protocol.
I manage to send the whole syze of the file, but when the client creates the file, it cant be open. In this case, im sending an jpg file.
heres the code for server.c:
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h>
#define PORT 59000
int main(int argc,char *argv[]) {
int port, fd, newfd, n, nw, addrlen;
int port_was_given = 0;
char buffer[128], *ptr, *topic, *data;
size_t result;
struct hostent *h;
struct sockaddr_in addr;
FILE *send;
if((fd=socket(AF_INET,SOCK_STREAM,0))==-1)exit(1); //error
memset((void*)&addr,(int)'\0',sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY);
if (argc == 3) {
port = atoi(argv[2]);
port_was_given = 1;
}
if(port_was_given == 1)
addr.sin_port=htons((u_short)port);
else
addr.sin_port=htons((u_short)PORT);
if(bind(fd,(struct sockaddr*)&addr,sizeof(addr))==-1)exit(1); //error
if(listen(fd,5)==-1)exit(1); //error
while(1) {
addrlen=sizeof(addr);
if((newfd=accept(fd,(struct sockaddr*)&addr,&addrlen))==-1)exit(1); //erro
h=gethostbyaddr((char*)&addr.sin_addr,sizeof(struct in_addr),AF_INET);
while((n=read(newfd,buffer,128))!=0) {
if(n==-1)exit(1);
topic = strtok(buffer," ");
topic = strtok(NULL," ");
if (strcmp(topic, "Nacional\n")==0) {
send = fopen("flag","r");
fseek(send, 0L, SEEK_END); //vai ate ao fim do ficheiro
int sz = ftell(send); //size of file
fseek(send,0L,SEEK_SET);
//rewind(send);
data = (char*)malloc(sizeof(char)*sz);
result = fread(data,1,sz,send);
//fseek(send,0L,SEEK_SET);
fclose(send);
char ptr2[300] = "REP ok ";
char *ptrInt; //for s -> int
sprintf(ptrInt, "%d", sz);
strcat(ptr2, ptrInt);
strcat(ptr2, " ");
strcat(ptr2, data);
strcat(ptr2, "\n");
while(n>0) {
nw=write(newfd,ptr2,n); //write n bytes on each cycle
}
}
}
close(newfd);
}
close(fd);
exit(0);
}
Ok so the logic is: client requests a type of content, in this case the content is "Nacional", so the server has to send the "flag.jpg" to the client.
The answer of the server has the following type:
REP status size data
In which status can be "ok" or "nok". If "nok" then the file is not sent.
size is the size of the data.
data is data of the file itself.
Now the client.c:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h>
#define PORT 58000
#define NG 10
int main (int argc,char *argv[])
{
/** ... variables declarations and other stuff ... */
fdtcp=socket(AF_INET,SOCK_STREAM,0);
if (fdtcp==-1) exit(1); // Erro
inet_aton(ip, &address);
if (strcmp(lsname, "localhost")==0)
newHost = gethostbyname("localhost");
else
newHost = gethostbyaddr((const void *)&address,sizeof ip,AF_INET);
newPort = atoi(newport);
memset((void*)&addrtcp,(int)'\0',sizeof(addrtcp));
addrtcp.sin_family=AF_INET;
addrtcp.sin_addr.s_addr=((struct in_addr *)(newHost->h_addr_list[0]))->s_addr;
addrtcp.sin_port=htons((u_short)newPort);
k = connect(fdtcp,(struct sockaddr*)&addrtcp,sizeof(addrtcp));
if (k==-1) exit(1); // Erro
// REQ Tn (Conteudo Solicitado)
ptr = strcat(reqdata, tn);
ptr = strcat(reqdata, "\n");
// Envia-se o Comando REQ
nreqleft = 25;
while(nreqleft>0) {
kwrite=write(fdtcp,ptr,nreqleft);
if (kwrite<=0) exit(1); // Erro
nreqleft -= kwrite;
ptr += kwrite;
}
// Recebe-se o Comando REP
nreqleft = 128;
ptr = &buffertcp[0];
kread=read(fdtcp,ptr,nreqleft);
if (kread==-1) exit(1); // Erro
cmd = strtok(buffertcp, " "); // REP
cmd = strtok(NULL, " "); // Status
if(strcmp(cmd,"ok")) {
printf("ERR\n");
exit(1); // Erro
}
cmd = strtok(NULL, " "); // Size
size = atoi(cmd);
// Recebem-se os Dados do Conteúdo Desejado
nreqleft = size;
char data[size];
ptr = &data[0];
while(nreqleft>0) {
kread=read(fdtcp,ptr,nreqleft);
if (kread==-1) exit(1); // Erro
nreqleft -= kread;
ptr += kread;
}
file = fopen("file","w");
fwrite(data, 1, size, file);
fclose(file);
close(fdtcp);
// --------------------------------------------------- //
exit(0);
}
The "other stuff" part is just variables declarations and a UDP connection with another server which has nothing to do with this part, so I'm 100% sure it won't affect this part. In fact, on client.c, if I place an printf of the message received from the server, it will show "REP ok 31800 ?????" which ??? I assume would be the data of the file.
The problem is that the "file" created can't be open. Help?
One problem is that 31800 is much larger than 300, and so when you append the data to your ptr2 array in the server, you have buffer overrun. You can correct that by not sending the data with a separate write() call after sending your "header" in ptr2. Your write() loop looks like it will loop forever, but I am guessing you are not showing all of your code.
In the receiver, I don't see any attempt to parse the header to separate the header from the data. Since you read in up to 128 bytes, that read may have received both the header and some data of the file, and you make no attempt to detect and save that part of the file.
When debugging file transfer applications, I would start with textual files so that you can visually see the resulting file, and run a simple diff on the file you saved with the actual file to see if there are differences.
i'm writing a server/client c program based on AX.25 protocol.
The server creating the socket, binding Successfully and listening for coming connections.
the client running in a different thread but fails on connect with " No route to host"
Server code
#include <sys/socket.h>
#include <netax25/ax25.h>
#include <netax25/axlib.h>
#include <netax25/axconfig.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <syslog.h>
#include <sys/types.h>
#include <linux/socket.h>
#include <stdlib.h>
#include <sys/un.h>
#include <string.h>
#include <errno.h>
int main(int argc,char **argv,char **envp) {
int ax25_socket = -1;
unsigned char buffer[512];
struct full_sockaddr_ax25 addr, axconnect ;
char *port ="3";// sm0 port number:3
char *call = "OH2BNS-8";// sm0 callsign
bzero((char *) &addr, sizeof(struct full_sockaddr_ax25));
addr.fsa_ax25.sax25_family = AF_AX25;
addr.fsa_ax25.sax25_ndigis = 1;
if (ax25_config_load_ports() == 0) {
printf( "Problem with axports file");
//return -1;
}
char* ax25port = (char*) ax25_config_get_addr(port);
ax25_aton_entry( call, addr.fsa_ax25.sax25_call.ax25_call);
ax25_aton_entry( ax25port, addr.fsa_digipeater[0].ax25_call);
ax25_socket = socket(AF_AX25, SOCK_SEQPACKET, 0);
if (ax25_socket < -1)
printf( "error in create socket");
if (bind(ax25_socket, (struct sockaddr *)&addr, sizeof(struct full_sockaddr_ax25)) < 0) {
perror("bind--");
return -1;
}
if(listen(ax25_socket,2) != 0)
{
printf("cannot listen on socket!\n");
close(ax25_socket);
return 0;
}
puts("listening");
//bzero((char *) &axconnect, sizeof(struct full_sockaddr_ax25));
int len =sizeof(struct full_sockaddr_ax25);
int temp_sock_desc = accept(ax25_socket, (struct sockaddr*)&axconnect, &len);
if (temp_sock_desc == -1)
{
printf("cannot accept client!\n");
close(ax25_socket);
return 0;
}
return 0;
}
Client code
#include <sys/socket.h>
#include <netax25/ax25.h>
#include <netax25/axlib.h>
#include <netax25/axconfig.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <syslog.h>
#include <sys/types.h>
#include <linux/socket.h>
#include <stdlib.h>
#include <sys/un.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int ax25_socket = -1;
unsigned char buffer[512];
struct full_sockaddr_ax25 axconnect ;
char *port ="3";// sm0 port number:3
char *call ="OH2BNS-8";// sm0 callsign
bzero((char *) &axconnect, sizeof(struct full_sockaddr_ax25));
axconnect.fsa_ax25.sax25_family = AF_AX25;
axconnect.fsa_ax25.sax25_ndigis = 1;
if (ax25_config_load_ports() == 0) {
printf( "Problem with axports file");
//return -1;
}
char* ax25port = (char*) ax25_config_get_addr(port);
ax25_aton_entry( call, axconnect.fsa_ax25.sax25_call.ax25_call);
ax25_aton_entry( ax25port, axconnect.fsa_digipeater[0].ax25_call);
ax25_socket = socket(AF_AX25, SOCK_SEQPACKET, 0);
if (ax25_socket < -1)
printf( "error in create socket");
if (connect(ax25_socket, (struct sockaddr *)&axconnect, sizeof(struct full_sockaddr_ax25)) != 0) {
perror("--");
switch (errno) {
case ECONNREFUSED:
printf("*** Connection refused\r");
break;
case ENETUNREACH:
printf("*** No known route\r");
break;
case EINTR:
printf("*** Connection timed out\r");
break;
default:
printf("ERROR: cannot connect to AX.25 callsign\r");
break;
}
close(ax25_socket);
}
printf("Connected!!\r");
int n = write(ax25_socket,"Message!!!!",18);
if(n = -1)
{
perror("write--");
}
return 0;
}
Simply put, a " No route to host"" would mean that there is no route for the server IP address in the client's routing table. Are you able to ping the server's IP address? Most likely you should not be able to and ping should say that the server is not reachable. If so, then this error has nothing to do with your program, you are probably running into a connectivity issue.
Can you find the entry for your server in the output of "route -n". If there is none, then you should check for a bigger prefix for the subnet of the server. If that also is not present, then you should confirm that you have a default route setup.
To further confirm, I would do the following two tests. First, what happens if you try to run the client/server on the same box? Second, what happens if you try to run the client/server on two boxes (present in the same subnet) and on the same LAN? If you do not see this issue and your application works just fine, then this should confirm that you are running into a connectivity issue.
I know this is an old question, but I would suspect a problem with ax25port - should be something like YOURCALL-0 where YOURCALL matches the HWaddr of an existing ax25 port ( try /sbin/ifconfig | fgrep AX.25
How can I get the IPv4 address of an interface on Linux from C code?
For example, I'd like to get the IP address (if any) assigned to eth0.
Try this:
#include <stdio.h>
#include <unistd.h>
#include <string.h> /* for strncpy */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
int
main()
{
int fd;
struct ifreq ifr;
fd = socket(AF_INET, SOCK_DGRAM, 0);
/* I want to get an IPv4 IP address */
ifr.ifr_addr.sa_family = AF_INET;
/* I want IP address attached to "eth0" */
strncpy(ifr.ifr_name, "eth0", IFNAMSIZ-1);
ioctl(fd, SIOCGIFADDR, &ifr);
close(fd);
/* display result */
printf("%s\n", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
return 0;
}
The code sample is taken from here.
In addition to the ioctl() method Filip demonstrated you can use getifaddrs(). There is an example program at the bottom of the man page.
If you're looking for an address (IPv4) of the specific interface say wlan0 then
try this code which uses getifaddrs():
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
struct ifaddrs *ifaddr, *ifa;
int family, s;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1)
{
perror("getifaddrs");
exit(EXIT_FAILURE);
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL)
continue;
s=getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if((strcmp(ifa->ifa_name,"wlan0")==0)&&(ifa->ifa_addr->sa_family==AF_INET))
{
if (s != 0)
{
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf("\tInterface : <%s>\n",ifa->ifa_name );
printf("\t Address : <%s>\n", host);
}
}
freeifaddrs(ifaddr);
exit(EXIT_SUCCESS);
}
You can replace wlan0 with eth0 for ethernet and lo for local loopback.
The structure and detailed explanations of the data structures
used could be found here.
To know more about linked list in C this page will be a good starting point.
My 2 cents: the same code works even if iOS:
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
showIP();
}
void showIP()
{
struct ifaddrs *ifaddr, *ifa;
int family, s;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1)
{
perror("getifaddrs");
exit(EXIT_FAILURE);
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL)
continue;
s=getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if( /*(strcmp(ifa->ifa_name,"wlan0")==0)&&( */ ifa->ifa_addr->sa_family==AF_INET) // )
{
if (s != 0)
{
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf("\tInterface : <%s>\n",ifa->ifa_name );
printf("\t Address : <%s>\n", host);
}
}
freeifaddrs(ifaddr);
}
#end
I simply removed the test against wlan0 to see data.
ps You can remove "family"
I have been in the same issue recently, and this is the code I made up and it works. Make sure to use the name of the network interface, exactly as you have it (could be "eth0" or else).
gotta check if ifconfigcommand beforehand to get the interface name and use it in C.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>
#include <linux/if.h>
#include <errno.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void extract_ipaddress()
{
//create an ifreq struct for passing data in and out of ioctl
struct ifreq my_struct;
//declare and define the variable containing the name of the interface
char *interface_name="enp0s3"; //a very frequent interface name is "eth0";
//the ifreq structure should initially contains the name of the interface to be queried. Which should be copied into the ifr_name field.
//Since this is a fixed length buffer, one should ensure that the name does not cause an overrun
size_t interface_name_len=strlen(interface_name);
if(interface_name_len<sizeof(my_struct.ifr_name))
{
memcpy(my_struct.ifr_name,interface_name,interface_name_len);
my_struct.ifr_name[interface_name_len]=0;
}
else
{
perror("Copy name of interface to ifreq struct");
printf("The name you provided for the interface is too long...\n");
}
//provide an open socket descriptor with the address family AF_INET
/* ***************************************************************
* All ioctl call needs a file descriptor to act on. In the case of SIOCGIFADDR this must refer to a socket file descriptor. This socket must be in the address family that you wish to obtain (AF_INET for IPv4)
* ***************************************************************
*/
int file_descriptor=socket(AF_INET, SOCK_DGRAM,0);
if(file_descriptor==-1)
{
perror("Socket file descriptor");
printf("The construction of the socket file descriptor was unsuccessful.\n");
return -1;
}
//invoke ioctl() because the socket file descriptor exists and also the struct 'ifreq' exists
int myioctl_call=ioctl(file_descriptor,SIOCGIFADDR,&my_struct);
if (myioctl_call==-1)
{
perror("ioctl");
printf("Ooops, error when invoking ioctl() system call.\n");
close(file_descriptor);
return -1;
}
close(file_descriptor);
/* **********************************************************************
* If this completes without error , then the hardware address of the interface should have been returned in the 'my_struct.ifr_addr' which is types as struct sockaddr_in.
* ***********************************************************************/
//extract the IP Address (IPv4) from the my_struct.ifr_addr which has the type 'ifreq'
/* *** Cast the returned address to a struct 'sockaddr_in' *** */
struct sockaddr_in * ipaddress= (struct sockaddr_in *)&my_struct.ifr_addr;
/* *** Extract the 'sin_addr' field from the data type (struct) to obtain a struct 'in_addr' *** */
printf("IP Address is %s.\n", inet_ntoa(ipaddress->sin_addr));
}
If you don't mind the binary size, you can use iproute2 as library.
iproute2-as-lib
Pros:
No need to write the socket layer code.
More or even more information about network interfaces can be got. Same functionality with the iproute2 tools.
Simple API interface.
Cons:
iproute2-as-lib library size is big. ~500kb.
I found a quite easy way to get ip, by take advantage of using bash command:
hostname -I
but use "hostname -I" natively will print the result on screen, we need to use "popen()" to read result out and save it into a string, here is c code:
#include <stdio.h> // popen
#include "ip_common_def.h"
const char * get_ip()
{
// Read out "hostname -I" command output
FILE *fd = popen("hostname -I", "r");
if(fd == NULL) {
fprintf(stderr, "Could not open pipe.\n");
return NULL;
}
// Put output into a string (static memory)
static char buffer[IP_BUFFER_LEN];
fgets(buffer, IP_BUFFER_LEN, fd);
// Only keep the first ip.
for (int i = 0; i < IP_BUFFER_LEN; ++i)
{
if (buffer[i] == ' ')
{
buffer[i] = '\0';
break;
}
}
char *ret = malloc(strlen(buffer) + 1);
memcpy(ret, buffer, strlen(buffer));
ret[strlen(buffer)] = '\0';
printf("%s\n", ret);
return ret;
}