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.
Related
I am currently studying TCP multiclient echo server and client using fork, thread, multiplexing IO and so on.
Below are the simple server and client using fork().
server_fork.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <arpa/inet.h>
static const int BUFSIZE = 1024;
int readn(int fd, char *buf, short n);
int main(void)
{
int cnt = 0;
int listenFD, connectFD;
struct sockaddr_in listenSocket, connectSocket;
char buffer [BUFSIZE];
if ((listenFD = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket() error\n");
exit(0);
}
if (setsockopt(listenFD, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int)) < 0) {
perror("sockopt error\n");
exit(0);
}
memset(&listenSocket, 0, sizeof(listenSocket));
listenSocket.sin_family = AF_INET;
listenSocket.sin_addr.s_addr = inet_addr("0.0.0.0");
listenSocket.sin_port = htons(7777);
if (bind(listenFD, (struct sockaddr *)&listenSocket, sizeof(listenSocket)) < 0) {
perror("bind() error\n");
exit(0);
}
if (listen(listenFD, 1) < 0) {
perror("listen() error\n");
exit(0);
}
signal(SIGCHLD, SIG_IGN);
int connectSocketLen;
short readLen;
pid_t pid;
while (1) {
connectSocketLen = sizeof(connectSocket);
if ((connectFD = accept(listenFD, (struct sockaddr *)&connectSocket,
&connectSocketLen)) < 0) {
perror("accept() error\n");
exit(0);
}
pid = fork();
cnt++;
if (pid == 0) {
close(listenFD);
while (1) {
memset(buffer, 0, BUFSIZE);
if (readn(connectFD, buffer, 2) == 0) {
break;
}
readLen = (*(short *)&buffer);
if(readLen != 12)
printf("[%d] : %d\n", cnt, readLen);
if (readn(connectFD, buffer, readLen) == 0) {
break;
}
buffer[readLen] = 0;
int n;
if ((n = write(connectFD, buffer, readLen)) <= 0) {
perror("!!");
}
sleep(0);
}
close(connectFD);
exit(0);
}
else if (pid > 0) {
close(connectFD);
}
else {
perror("fork() error\n");
exit(0);
}
}
close(listenFD);
return 0;
}
int readn(int fd, char *buf, short n)
{
short sp = 0, readed;
while (n) {
readed = read(fd, buf + sp, n);
if (readed <= 0) {
return 0;
}
n -= readed;
sp += readed;
}
return 1;
}
client.c
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
static const int bufSize = 1024;
int main(int argc,char *argv[])
{
signal(SIGCHLD, SIG_IGN);
fork();
fork();
fork();
fork();
fork();
fork();
fork();
fork();
//fork();
//fork();
char length[2], recvBuf[bufSize];
char buf[]="hello, world\0";
short len = strlen(buf);
sprintf(length,"%c",len);
int client_sockfd, size, i, n, state;
uint64_t delta_us = 0;
struct sockaddr_in server_addr;
struct timespec start, end;
client_sockfd = socket(PF_INET, SOCK_STREAM, 0);
memset(&server_addr, 0, sizeof server_addr);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(7777);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr.s_addr);
state = connect(client_sockfd, (struct sockaddr *)&server_addr,
sizeof server_addr);
if (state < 0) {
perror("connect err");
exit(1);
}
for (i=0;i<10;i++) {
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
n = write(client_sockfd, length, sizeof length);
if (n<=0) {
perror("write err");
exit(1);
}
n = write(client_sockfd, buf, *((short *)&length));
if (n<=0) {
perror("write err");
exit(1);
}
n = read(client_sockfd, recvBuf, *((short *)&length));
if (n<=0) {
perror("read err");
exit(1);
}
clock_gettime(CLOCK_MONOTONIC_RAW, &end);
delta_us += (end.tv_sec - start.tv_sec) * 1000000 +
(end.tv_nsec - start.tv_nsec)/1000;
printf("%lu\n", delta_us);
sleep(1);
}
return 0;
}
The client first transmits the length of the message represented by 2 bytes.
Then client sends a "hello, world" message to the server in buf.
The server first reads 2 bytes through readn () and reads the message as much.
But in all cases (fork, thread, multiplexing IO... whatever), I have a common difficulty.
The problem is that : In the above source code, the length of the message("hello, world" is 12. so it is expected to read 12 in the first readn () of the server.
In fact, when the number of clients is small (the number of forks on the client is 7 or less), it works fine.
However, if the number of clients increases, the value of readLen will be 25960 on some connections. 25960 is the value that represents "he" in hex.
Why is this problem happening when there are many clients?
I wonder if it is the same as sending a TCP packet at one time and dividing it two times.
Below is a tcpdump capture of the above problem situation.
I'm sorry that I could not upload the image right away.
tcpdump
On the client side, you have multiple problems surrounding how you send the message length. Starting here:
char length[2], recvBuf[bufSize];
char buf[]="hello, world\0";
short len = strlen(buf);
sprintf(length,"%c",len);
Your sprintf format promises that the third argument will be of type char (promoted to int), and instructs it to output the corresponding character into the string. In fact, the argument is a short (promoted to int), and this mismatch produces undefined behavior.
In practice, the overall sprintf call is probably equivalent to this:
length[0] = (char)(int)len;
length[1] = '\0';
That has implementation-defined characteristics if char is a signed type, but in any event, it cannot capture a length greater than the maximum value that can be represented by an unsigned char.
The client goes on to do this:
n = write(client_sockfd, length, sizeof length);
That's not inherently wrong, but it does fail to accommodate the possibility of a short write. Moreover, the server does not interpret this part of the message in a manner consistent with the way it was prepared:
if (readn(connectFD, buffer, 2) == 0) {
break;
}
readLen = (*(short *)&buffer);
As it turns out, that combination might happen to work if the server uses a 16-bit, little-endian representation for type short (subject to the restriction I already described on representable message length) and an execution character set compatible with the client's, but those are not safe assumptions for network software in general.
In part, you seem to be missing an important point about read() and write() and char pointers: a char * can be used to read the representation of an object of any type, so you do not need to move your data into a char array in order to send or receive it.
Overall, this would be a more appropriate approach:
// Client:
uint16_t len = strlen(buf); // risk: buf may be too long
uint16_t len_n = htons(len);
int n = writen(client_sockfd, &len_n, 2); // a write() analog of readn()
// ... handle possible error ...
// Sever:
uint16_t len_n;
int n = readn(connectFD, &len_n, 2);
// ... possible handle error ...
uint16_t readLen = ntohs(len_n);
Note that there is no need to copy the length into a separate char array to send it, nor to receive it into a char array. On the other hand, note also the use of a specified-size data type (uint16_t) on both sides, and the use of htons() and ntohs() to ensure that the client and server interpret the bytes of the data the same way. Furthermore, note the use of a write analog of readn() to send the data, which otherwise could be sent incompletely.
By the same token the client and server should both use the (hypothetical) writen() function to send the text of the message, and just like the server, the client should use readn() to read it. Failing to account for the possibility of short reads and writes is a significant flaw, especially in a protocol such as yours whose message boundaries are not easily distinguishable from data. An unnoticed short read or write will cause your client and server to fall out of sync, with no easy way to recover.
Apart from the problems already noticed by #JohnBollinger, you only use a listen window of 1 in server.c when all your forked client processes try to connect at the same time. It caused plenty of connect : conn reset by peer errors in my tests. I had to use a window greater than 64 on my FreeBSD (no errors at 256) to get rid of them :
if (listen(listenFD, 256) < 0) {
perror("listen() error\n");
exit(0);
}
I have this C code:
#include <errno.h>
#include <sys/errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
char *buf;
int c,s; int port=45678;
int recv_m(int c,char *buf);
void get(){
char fileNameBuf[20];
int i=0;
char *s = buf;
if (*s=='/') {
s++;
while (*s!=' ') {
fileNameBuf[i]=*s;
*s++;
i++;
}
fileNameBuf[i]='\0';
}
}
int main(){
//server connected
while ((c = accept(s, (struct sockaddr *) &client, (socklen_t *) &clientlen)) > 0){
// Do whatever a web server does.
char recv_buf[50];
char *r=recv_buf;
while(recv(c, r , 1, 0)!=0){
//stores the received message in recv_buf
}
recv_buf[i]='\0';
if (strncmp(recv_buf, "GET ", 4)==0){
buf=recv_buf+4;
get();
}
}
return (0);
}
*buf points to string /index.html HTTP/1.0. At the end of the function, fileNameBuf should store the string index.html.
The number of times in the while loop should be 10. When I run this code, i = 381 and I get a segmentation fault (core dump).
What am I doing wrong?
Here is the whole code, so *buf is the problem?
Either your assumptions about what is in buf must be faulty — or we're faulty in our interpretation of what you mean when you say:
*buf points to string "/index.html HTTP/1.1".
If you declared char **buf; and set:
char *str = "/index.html HTTP/1.1";
char **buf = str;
Then *buf points to the start of the string. This is why creating an SSCCE (Short, Self-Contained, Correct Example) is important; it removes the ambiguities.
An SSCCE
This code:
#include <stdio.h>
const char *buf = "/index.html HTTP/1.1";
static
void get(void)
{
char fileNameBuf[10];
int i=0;
if (*buf=='/')
{
buf++;
while (*buf!=' ')
{
fileNameBuf[i]=*buf;
buf++;
i++;
printf("%d\n", i);
}
}
printf("%.*s\n", (int)sizeof(fileNameBuf), fileNameBuf);
}
int main(void)
{
get();
return 0;
}
produces this output:
1
2
3
4
5
6
7
8
9
10
index.html
Granted, I had to take care not to print beyond the end of the array. Your array is minimally sized; it cannot hold a string containing the file name (no space for the null terminator). But it should not crash — if char *buf = "/index.html HTTP/1.1";!
Completed code — stage 1
This is closely based on what was submitted as the program. It compiles cleanly — I've not tried running it.
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
char *buf;
int c, s; int port = 45678;
struct sockaddr_in server, client;
char *ipaddress = "127.0.0.1";
int clientlen = sizeof(client);
int portset = 0;
int recv_m(int c, char *buf);
static
void get(void)
{
printf("in get method\n");
char fileNameBuf[20];
int i = 0;
printf("%s\n", buf);
char *s = buf;
if (*s == '/')
{
printf("buf==/\n");
s++;
while (*s != ' ')
{
// printf("%c\n",*buf);
// printf("in while\n");
fileNameBuf[i] = *s;
s++;
i++;
printf("%d\n", i);
}
fileNameBuf[i]='\0';
printf("<<%s>>\n", fileNameBuf);
}
else
{
printf("!= '/'\n");
}
}
int main(void)
{
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);
// if (!inet_aton(ipaddress, &server.sin_addr))
// fprintf (stderr, "inet_addr() conversion error\n");
s = socket(AF_INET, SOCK_STREAM, 0); // Create socket
if (!s) {
perror("socket");
exit(0);
}
if (bind(s, (struct sockaddr *) &server, sizeof(server)) < 0) {
perror("bind");
exit(0);
}
printf("binded\n");
if (listen(s, SOMAXCONN) < 0) {
perror("listen");
exit(0);
}
printf("Waiting for connection\n");
while ((c = accept(s, (struct sockaddr *) &client, (socklen_t *) &clientlen)) > 0)
{
// Do whatever a web server does.
printf("got connected\n");
char recv_buf[50];
char el[4] = "\r\n\r\n";
int h = 0; int i = 0;
char *r = recv_buf;
while (recv(c, r, 1, 0) != 0)
{
if (h == 4) break;
if (*r == el[h]) {
h++;
}
r++;
i++;
if (h == 4) break;
}
recv_buf[i] = '\0';
printf("%s\n", recv_buf);
if ( strncmp(recv_buf, "GET ", 4) == 0) {
printf("check get\n");
buf = recv_buf+4;
printf("%s\n", buf);
get();
}
}
return(0);
}
This is not an SSCCE. All the code related to setting up the socket and reading from the socket should be tangential to the problem at hand.
Reduced Code — Stage 2
The reduction process involves eliminating the inessential.
#include <stdio.h>
#include <string.h>
char *buf;
static void get(void)
{
printf("in get method\n");
char fileNameBuf[20];
int i = 0;
printf("%s\n", buf);
char *s = buf;
if (*s == '/')
{
printf("buf==/\n");
s++;
while (*s != ' ')
{
fileNameBuf[i] = *s;
s++;
i++;
printf("%d\n", i);
}
fileNameBuf[i]='\0';
printf("<<%s>>\n", fileNameBuf);
}
else
{
printf("!= '/'\n");
}
}
int main(void)
{
char recv_buf[50];
strcpy(recv_buf, "GET /index.html HTTP/1.1\r\n\r\n");
printf("<<%s>>\n", recv_buf);
if (strncmp(recv_buf, "GET ", 4) == 0)
{
printf("check get\n");
buf = recv_buf+4;
printf("%s\n", buf);
get();
}
return(0);
}
This too compiles cleanly; unfortunately, it also runs successfully for me (GCC 4.8.1, Mac OS X 10.8.4):
<<GET /index.html HTTP/1.1
>>
check get
/index.html HTTP/1.1
in get method
/index.html HTTP/1.1
buf==/
1
2
3
4
5
6
7
8
9
10
<<index.html>>
This happens sometimes; you are too ruthless in your clean-up. So, you have to go back to the previous code and remove things more slowly.
Retrenching — Stage 3
Let's take the full code from Stage 1 and run it locally. The browser can connect to localhost:45678/index.html and the output is:
binded
Waiting for connection
got connected
GET /index.html HTTP/1.1
Host: localhost:45678
check get
/index.html HTTP/1.1
Host: localhost:45678
in get method
/index.html HTTP/1.1
Host: localhost:45678
buf==/
1
2
3
4
5
6
7
8
9
10
<<index.html>>
There is nothing sent back to the waiting browser (it's still waiting, but will time out shortly). The code loops back to the next accept; it isn't clear that it shuts up shop properly, but it didn't crash on the first cycle.
So, this has been a somewhat fruitless exercise...your code seems to work OK. It should still be improved — starting off by making every one of those global variables into a local in main(), and then passing buf to a modified get() with the signature void get(char *buf).
Does the code you showed really crash for you? If so, what does the debugger say about why it crashes?
Bullet-proofing — Stage 4
After establishing that the string pointed to by buf was actually "/index.html\r\n\r\n" and not"/index.html HTTP/1.1\r\n\r\n"`, it is clear that I was remiss in not ensuring that the code would not read past the end of null terminated strings nor write past the ends of buffers. However, this is precisely why an SSCCE is so important, and why diagnostic printing is so important. If the question had included the actual string that was being scanned, it would have been a lot simpler to spot the issue.
This code is more nearly bullet-proof. Amongst other major changes, it attempts to read the request in a single recv() operation, rather than reading the request byte by byte. This puts the onus on avoiding an overflow on recv(). All the global variables are gone; buf is passed to get() as an argument. get() has been written to detect EOS and overlong names, as well as handling names up to the first space. It still has the debug code for each character in the file name. The code in main() has been dolled up to send back a response that is valid HTTP — or valid enough HTTP — with a bit of HTML that changes each time it is handled. It's interesting seeing the requests the browser makes. There's also an error reporting function that writes to standard error, takes a format string and arguments as with printf() et al, and also adds the correct error number and message for the system error, and then exits with a failure status. This makes error reporting less painful; a one-line call suffices for each error, instead of 3 or 4 lines (depending on your choice of formatting). The errors can be more expressive than perror() too.
#include <ctype.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <unistd.h>
static void err_exit(const char *fmt, ...);
static
void get(char *buf)
{
printf("in get method\n");
char fileNameBuf[256];
size_t i = 0;
printf("%s\n", buf);
char *s = buf;
if (*s == '/')
{
printf("buf==/\n");
s++;
while (*s != '\0' && *s != ' ' && i < sizeof(fileNameBuf))
{
printf("i = %3d: c = %3d = 0x%.2X = '%c'\n",
(int)i, *s, *s & 0xFF, isprint(*s) ? *s : '.');
fileNameBuf[i++] = *s++;
}
fileNameBuf[i]='\0';
printf("<<%s>>\n", fileNameBuf);
}
else
{
printf("!= '/'\n");
}
}
int main(void)
{
char *buf;
int fd;
int s;
int port = 45678;
struct sockaddr_in server, client;
int clientlen = sizeof(client);
int msgnum = 314159;
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);
s = socket(AF_INET, SOCK_STREAM, 0);
if (!s)
err_exit("socket()\n");
if (bind(s, (struct sockaddr *) &server, sizeof(server)) < 0)
err_exit("bind()\n");
printf("bound to address\n");
if (listen(s, SOMAXCONN) < 0)
err_exit("listen()\n");
printf("Waiting for connection\n");
while ((fd = accept(s, (struct sockaddr *) &client, (socklen_t *) &clientlen)) > 0)
{
printf("got connection\n");
char recv_buf[4096];
char el[5] = "\r\n\r\n";
ssize_t length;
/* Read message in one go; leave space for a null at the end */
if ((length = recv(fd, recv_buf, sizeof(recv_buf)-1, 0)) > 0)
{
recv_buf[length] = '\0';
if (strstr(recv_buf, el) == 0)
err_exit("Incomplete message (%d bytes and no CRLF, CRLF pair)\n", length);
printf("%d: <<%s>>\n", (int)length, recv_buf);
if (strncmp(recv_buf, "GET ", 4) == 0)
{
printf("check get\n");
buf = recv_buf + 4;
printf("<<%s>>\n", buf);
get(buf);
char message[256];
char format1[] =
"<html><head><title>Hello World!</title></head>"
"<body><h1>This is no fun at all (%d).</h1></body></html>\r\n\r\n";
int msg_len = snprintf(message, sizeof(message), format1, msgnum++);
char format2[] =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Content-Length: %d\r\n"
"Content-Encoding: UTF-8\r\n\r\n%s";
char response[1024];
size_t nbytes = snprintf(response, sizeof(response), format2,
msg_len, message);
write(fd, response, nbytes);
}
}
close(fd);
}
return(0);
}
static void err_exit(const char *fmt, ...)
{
int errnum = errno;
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "%d: %s\n", errnum, strerror(errnum));
exit(1);
}
It appears that buf is a char array. If so, you should access the buf using a char pointer. Try this:
int main () {
char buf[] = "/index.html HTTP/1.0";
char fileNameBuf[10];
int i=0;
char *s = buf;
if (*s=='/') {
s++;
while (*s!=' ') {
fileNameBuf[i]=*s;
*s++;
i++;
printf("%d\n",i);
}
}
}
If buf is an array of char and even though arrays and pointers have several things in common, doing buf++ is not legal by C.Here is a text from Kernighan/Ritchie C book. You have probably buf declared as an array as well.
There is one difference between an array name and a pointer that must be kept in mind. A pointer is a variable, so pa=a and pa++ are legal. But an array name is not a variable; constructions like a=pa and a++ are illegal.
Due to this reason, doing "arr++" would be an error in the following code.
int main() {
int arr[10];
int *ptr = arr;
arr++; // Would be illegal.
ptr++; // This is okay.
}
I am trying to send audio file from one computer to other using socket programming in c. When I send simple string without any framing information such as header or tailer it gets sent perfectly. But when I try to send the same information with some header information like size of the socket_data or packet_no. it doesn't get sent properly. Even the terminal output is SAME on both the machines but the file which gets created is totally different and unplayable. I have used serializing concept to send packet. Am attaching codes. Please comment whats going wrong.
Server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
void set_socket(struct sockaddr_in *socket, int type, int host_short, int addr_type)
{
socket -> sin_family = type;
socket -> sin_port = htons(host_short);
socket -> sin_addr.s_addr = htonl(addr_type);
}
void serialize(char *buffer, int count, char *data)
{
int i=0, j=0;
char temp1[20];
sprintf(temp1, "%d", count);
while(temp1[i] != '\0')
{
buffer[j++] = temp1[i++];
}
buffer[j++]=' ';
for(i=0; data[i] != '\0'; i++)
{
buffer[j++] = data[i];
}
buffer[j] = '\0';
printf("BUFFER =%ld\n", sizeof(buffer));
}
int main()
{
int sid = 0, bid = 0, fp;
char *send_data = (char *)malloc(1024*sizeof(char));
char temp[1024];
char *receive_data = (char *)malloc(1024*sizeof(char));
int fd, count, cnt=0;
struct sockaddr_in server_socket, client_socket;
int size = sizeof(client_socket);
if((sid = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
printf("Connection error..\n");
exit(1);
}
set_socket(&server_socket, AF_INET, 6000, INADDR_ANY);
if((bid = bind(sid, (struct sockaddr *)&server_socket, sizeof(struct sockaddr))) == -1)
{
printf("Binding error..\n");
exit(1);
}
printf("I am waiting for client..\n");
recvfrom(sid, receive_data, 1024, 0,(struct sockaddr *)&client_socket, &size);
printf("received data is : %s\n", receive_data);
fd = open(receive_data, O_RDONLY);
printf("size = %ld\n", sizeof(send_data));
while((count=read(fd, temp, 500)) != 0)
{
printf("I am inside the loop : %d\n", cnt++);
serialize(send_data, count, temp);
printf("Serialized : %s\n", send_data);
sendto(sid, send_data, 1024, 0, (struct sockaddr *)&client_socket, size);
}
printf("I am outside the loop : %d\n", count);
strcpy(temp, "ENDOFFILE");
serialize(send_data, sizeof(temp), temp);
sendto(sid, send_data, 1024, 0, (struct sockaddr *)&client_socket, size);
fcloseall();
close(sid);
close(fd);
return 0;
}
Client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
void set_socket(struct sockaddr_in *socket, int type, int host_short)
{
socket -> sin_family = type;
socket -> sin_port = htons(host_short);
}
void deserialize(char *buffer, int *size, char *data)
{
int i=0, j=0;
char temp1[20];
while(buffer[i] != ' ')
{
temp1[j++] = buffer[i++];
}
temp1[j] = '\0';
printf("\nINT : %s\n", temp1);
*size = atoi(temp1);
i++;
j=0;
while(buffer[i] != '\0')
{
data[j++] = buffer[i++];
}
data[j++] = '\0';
}
int main()
{
int sid = 0, bid = 0, con = 0;
char *send_data = (char *)malloc(1024*sizeof(char));
char *receive_data = (char *)malloc(1024*sizeof(char));
char *temp = (char *)malloc(1024*sizeof(char));
struct hostent *host;
struct sockaddr_in server_socket;
int size = sizeof(server_socket);
if((sid = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
printf("Connection error at client side..\n");
exit(1);
}
set_socket(&server_socket, AF_INET, 6000);
if (inet_aton("127.0.0.1", &server_socket.sin_addr)==0)
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
printf("Enter the name of the file you want to see : ");
scanf("%s", send_data);
int fd = open("sanket.mp3", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IXUSR);
sendto(sid, send_data, 1024, 0, (struct sockaddr *)&server_socket, size);
printf("================= Contents of the File =====================\n");
while(1)
{
int size;
recvfrom(sid, temp, 1024, 0, (struct sockaddr *)&server_socket, &size);
printf("Deserialize it : %s\n",temp);
deserialize(temp, &size, receive_data);
if(!strcmp(receive_data, "ENDOFFILE"))
{
printf("============================================================\n");
break;
}
else
write(fd, receive_data, size);
}
fcloseall();
close(sid);
return 0;
}
When I checked the size of the sent and received file, sizes are same but the contents are different, thus I am unable to play received audio file.
You seem to be reading from a binary data-file, yet inside your serialize function you are treating the data as-if it were null-terminated string data. For instance, this loop inside serialize:
for(i=0; data[i] != '\0'; i++)
{
buffer[j++] = data[i];
}
will terminate on the first zero-value it encounters. If this is true binary data from your audio file though, then I'm sure you'll get 0 values that are actual audio data rather than indicating the end of the buffer. Instead of terminating on a NULL-value, you should be terminating on the size of the buffer that you're passing to serialize that was read in your call to read in the while-loop. That way you can be sure you are getting all the data that was read from your read call packed into your send-buffer.
Secondly, printing sizeof(buffer), when buffer is a pointer, will only print the size of a pointer-type, not the size of the actual buffer the pointer is pointing to. Again, you're going to have to explicitly pass that value to your serialize function.
Third, you're terminating the buffer with a null-value ... again, that's not going to be a good idea based on the first point about this being raw binary data and not null-terminated strings. You should either come up with some type of string to indicate the end-of-transmission in the buffer that would be a set of values that would be impossible to be part of the data, or you should explicitly read the number of bytes that are in the "count" that you've embedded in the packet data.
Finally, you're not really serializing your data ... the concept of serializing typically means to transfer the data in a platform-independent way. You're simply packing up the bytes read and sending them across the network, assuming that the receiving side has the same endianness, etc. A fairly simple serialization approach would do something like creating ASCII strings from all the data-values, with the downside that this will create quite a bit of data-bloat. There are other cross-platform standards for serialized data such as JSON, SOAP, etc.
I am trying to obtain the MAC addresses of all of my interface on OSX using C. The common ways to obtain it Linux dont work on BSD - from everything I have seen, you must obtain the interfaces and look for the ones that are of type AF_LINK. My problem is that the LLADDR(sockaddr_dl) gives me a whole bunch of data (which includes my MAC) and I dont know what format the data is in. For example; the following code will output:
Device: en1
link sdl_alen: 101 mac:
31:f8:1e:df:d6:22:1d:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:b0:06:10:00:01:00:00:00:c0:02:10:00:01:00:00:00:00:00:00:00:00:00:00:00:40
:03:10:00:01:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:03:00:6c:6f:30:00:00:00:00:00:00:00:00:00:00:00:00:00:70:03:10:00:01:00:00:00:e0:
02:10:00:01:00:00:
My MAC is bolded. It seems that this is the format all of the time, but I would be a lot more comfortable if I could cast LLADDR(sockaddr_dl) to something. In the net/if_dl.h, LLADDR is defied as:
#define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen))
which, as far as I can tell, is saying that the results are of type (void *) - no help.
Other posts like:
Having a problem figuring out how to get Ethernet interface info on Mac OS X using ioctl/SIOCGIFADDR/SIOCGIFCONF?
seem to think they have it figured out, but if you look through the code, you can see it will not work due to sdl_alen not being 6.
int main() {
pcap_if_t *alldevs;
pcap_if_t *d;
pcap_addr_t *alladdrs;
pcap_addr_t *a;
struct sockaddr_dl* link;
char eb[PCAP_ERRBUF_SIZE];
char *addr_buf[40];
if (pcap_findalldevs(&alldevs, eb) == -1) {
printf("no devs found\n");
return(-1);
}
for (d = alldevs; d != NULL; d = d->next) {
printf("Device: %s\n", d->name);
alladdrs = d->addresses;
for (a = alladdrs; a != NULL; a = a->next) {
if(a->addr->sa_family == AF_LINK && a->addr->sa_data != NULL){
// MAC ADDRESS
//struct sockaddr_dl *sdl = (struct sockaddr_dl *) a->addr->sa_data;
link = (struct sockaddr_dl*)a->addr->sa_data;
char mac[link->sdl_alen];
caddr_t macaddr = LLADDR(link);
memcpy(mac, LLADDR(link), link->sdl_alen);
printf("link sdl_alen: %i\n", link->sdl_alen);
int i;
printf("mac: ");
for(i = 0; i<link->sdl_alen; i++){
printf("%02x:", (unsigned char)mac[i]);
}
printf("\n");
}
}
}
}
The problem is that you are casting the sockaddr->sa_data to sockaddr_dl instead of casting the sockaddr itself to sockaddr_dl. Keep in mind that sockaddr_dl is an OS X/BSD thing, so #ifdef that part for portability.
Don't do:
link = (struct sockaddr_dl*)a->addr->sa_data;
Do:
link = (struct sockaddr_dl*)a->addr;
Then you will get the correct sdl_alen and things will work with out any hacks. And if you want to really easily get the name of addresses that may be either AF_INET, AF_INET6, or AF_LINK use getnameinfo():
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <net/if_dl.h>
int get_sock_len(struct sockaddr *sa)
{
switch (sa->sa_family) {
case AF_INET:
return sizeof(struct sockaddr_in);
case AF_INET6:
return sizeof(struct sockaddr_in6);
case AF_LINK:
return sizeof(struct sockaddr_dl);
default:
return -1;
}
}
int get_numeric_address(struct sockaddr *sa, char *outbuf, size_t buflen) {
socklen_t len;
if ((len = get_sock_len(sa)) < 0) {
return -1;
}
if (getnameinfo(sa, len, outbuf, buflen, NULL, 0, NI_NUMERICHOST)) {
return -1;
}
return 0;
}
...
char buf[NI_MAXHOST];
if (!get_numeric_address(sa, buf, sizeof(buf))) { /* For some struct sockaddr *sa */
printf("address: %s\n", buf);
} else {
printf("doh!\n");
}
Here is what I ended up doing:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <errno.h>
#include <net/if_dl.h>
#include <pcap.h>
#include "mac.h"
int main() {
printf("en1: %s\n", lookupDeviceMac("vnic0"));
}
unsigned char *lookupDeviceMac(char *dev){
pcap_if_t *alldevs;
pcap_if_t *d;
pcap_addr_t *alladdrs;
pcap_addr_t *a;
struct sockaddr_dl* link;
char eb[PCAP_ERRBUF_SIZE];
char *ret = malloc(6);
if (pcap_findalldevs(&alldevs, eb) == -1) {
printf("%s\n", eb);
return(ret);
}
for (d = alldevs; d != NULL; d = d->next) {
if(strcmp(d->name, dev) == 0){
printf("Device: %s\n", d->name);
alladdrs = d->addresses;
for (a = alladdrs; a != NULL; a = a->next) {
if(a->addr->sa_family == AF_LINK && a->addr->sa_data != NULL){
// MAC ADDRESS
//struct sockaddr_dl *sdl = (struct sockaddr_dl *) a->addr->sa_data;
link = (struct sockaddr_dl*)a->addr->sa_data;
char mac[link->sdl_alen];
caddr_t macaddr = LLADDR(link);
memcpy(mac, LLADDR(link), link->sdl_alen);
if(link->sdl_alen == 6){
// Seen in some sample code
sprintf(ret, "%02x:%02x:%02x:%02x:%02x:%02x",(unsigned char)mac[0],
(unsigned char)mac[1],
(unsigned char)mac[2],
(unsigned char)mac[3],
(unsigned char)mac[4],
(unsigned char)mac[5]);
} else if(link->sdl_alen > 6) {
// This is what happens in OSX 10.6.5
sprintf(ret, "%02x:%02x:%02x:%02x:%02x:%02x",(unsigned char)mac[1],
(unsigned char)mac[2],
(unsigned char)mac[3],
(unsigned char)mac[4],
(unsigned char)mac[5],
(unsigned char)mac[6]);
}
return(ret);
}
}
}
}
}
I was trying to see all devices reported by pcap_findalldevs and ended up here looking for information on interpreting AF_LINK addresses on MAC OS.
I'm used to seeing the struct sockaddr standing in for a interface family and being immediately cast to the appropriate type and not writing code to access *sa_data*.
For what I wanted it was sufficient to use link_ntoa to convert the address to a human readable form.
#import <Foundation/Foundation.h>
#include <pcap.h>
#include <netinet/in.h>
#include <net/if_dl.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
pcap_if_t* allDevs = NULL;
char errbuff[PCAP_ERRBUF_SIZE];
if (pcap_findalldevs(&allDevs, errbuff) <0) {
NSLog(#"Failed with error '%s'", errbuff);
}
else {
for (pcap_if_t* device = allDevs; device != NULL; device = device->next) {
for (pcap_addr_t* address = device->addresses; address != NULL; address = address->next) {
struct sockaddr* sa_addr = address->addr;
if (sa_addr->sa_family == AF_LINK) {
struct sockaddr_dl* link_addr = (struct sockaddr_dl*) sa_addr;
char* linkAddress = link_ntoa(link_addr);
NSLog(#"ntoa %s", linkAddress);
}
}
}
}
pcap_freealldevs(allDevs);
[pool drain];
return 0;
}
Running on my machine I get the following devices with AF_LINK entries.
2011-08-14 02:22:43.024 HomePlugToolHelper[12473:903] ntoa en0:0.16.cb.xx.x.xx
2011-08-14 02:22:43.027 HomePlugToolHelper[12473:903] ntoa fw0:0.16.cb.xx.xx.xx.xx.xx
2011-08-14 02:22:43.028 HomePlugToolHelper[12473:903] ntoa en1:0.16.cb.x.xx.xx
2011-08-14 02:22:43.028 HomePlugToolHelper[12473:903] ntoa lo0
I have looked around like crazy but don't get a real answer. I got one example, but that depended on the individuals own library so not much good.
At first I wanted to get the default gateway of an interface, but since different IP's could be routed differently I quickly understood that what I want it get the gateway to use for a given destination IP by using an AF_ROUTE socket and the rtm_type RTM_GET.
Does anyone have an example where I actually end up with a string containing the gateways IP (or mac address)? The gateway entry seem to be in hex but also encoded in /proc/net/route, where I guess the AF_ROUTE socket get's it info from (but via the kernel I guess).
Thanx in advance
and p.s.
I just started using stack overflow and I must say, all of you guys are great! Fast replies and good ones! You are my new best friends ;)
This is OS specific, there's no unified(or ANSI C) API for this.
Assuming Linux, the best way is to just parse /proc/net/route , look for the entry where Destination is 00000000 , the default gateway is in the Gateway column , where you can read the hex representation of the gateway IP address (in big endian , I believe)
If you want to do this via more specific API calls, you'll have to go through quite some hoops, here's an example program:
#include <netinet/in.h>
#include <net/if.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define BUFSIZE 8192
char gateway[255];
struct route_info {
struct in_addr dstAddr;
struct in_addr srcAddr;
struct in_addr gateWay;
char ifName[IF_NAMESIZE];
};
int readNlSock(int sockFd, char *bufPtr, int seqNum, int pId)
{
struct nlmsghdr *nlHdr;
int readLen = 0, msgLen = 0;
do {
/* Recieve response from the kernel */
if ((readLen = recv(sockFd, bufPtr, BUFSIZE - msgLen, 0)) < 0) {
perror("SOCK READ: ");
return -1;
}
nlHdr = (struct nlmsghdr *) bufPtr;
/* Check if the header is valid */
if ((NLMSG_OK(nlHdr, readLen) == 0)
|| (nlHdr->nlmsg_type == NLMSG_ERROR)) {
perror("Error in recieved packet");
return -1;
}
/* Check if the its the last message */
if (nlHdr->nlmsg_type == NLMSG_DONE) {
break;
} else {
/* Else move the pointer to buffer appropriately */
bufPtr += readLen;
msgLen += readLen;
}
/* Check if its a multi part message */
if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0) {
/* return if its not */
break;
}
} while ((nlHdr->nlmsg_seq != seqNum) || (nlHdr->nlmsg_pid != pId));
return msgLen;
}
/* For printing the routes. */
void printRoute(struct route_info *rtInfo)
{
char tempBuf[512];
/* Print Destination address */
if (rtInfo->dstAddr.s_addr != 0)
strcpy(tempBuf, inet_ntoa(rtInfo->dstAddr));
else
sprintf(tempBuf, "*.*.*.*\t");
fprintf(stdout, "%s\t", tempBuf);
/* Print Gateway address */
if (rtInfo->gateWay.s_addr != 0)
strcpy(tempBuf, (char *) inet_ntoa(rtInfo->gateWay));
else
sprintf(tempBuf, "*.*.*.*\t");
fprintf(stdout, "%s\t", tempBuf);
/* Print Interface Name*/
fprintf(stdout, "%s\t", rtInfo->ifName);
/* Print Source address */
if (rtInfo->srcAddr.s_addr != 0)
strcpy(tempBuf, inet_ntoa(rtInfo->srcAddr));
else
sprintf(tempBuf, "*.*.*.*\t");
fprintf(stdout, "%s\n", tempBuf);
}
void printGateway()
{
printf("%s\n", gateway);
}
/* For parsing the route info returned */
void parseRoutes(struct nlmsghdr *nlHdr, struct route_info *rtInfo)
{
struct rtmsg *rtMsg;
struct rtattr *rtAttr;
int rtLen;
rtMsg = (struct rtmsg *) NLMSG_DATA(nlHdr);
/* If the route is not for AF_INET or does not belong to main routing table
then return. */
if ((rtMsg->rtm_family != AF_INET) || (rtMsg->rtm_table != RT_TABLE_MAIN))
return;
/* get the rtattr field */
rtAttr = (struct rtattr *) RTM_RTA(rtMsg);
rtLen = RTM_PAYLOAD(nlHdr);
for (; RTA_OK(rtAttr, rtLen); rtAttr = RTA_NEXT(rtAttr, rtLen)) {
switch (rtAttr->rta_type) {
case RTA_OIF:
if_indextoname(*(int *) RTA_DATA(rtAttr), rtInfo->ifName);
break;
case RTA_GATEWAY:
rtInfo->gateWay.s_addr= *(u_int *) RTA_DATA(rtAttr);
break;
case RTA_PREFSRC:
rtInfo->srcAddr.s_addr= *(u_int *) RTA_DATA(rtAttr);
break;
case RTA_DST:
rtInfo->dstAddr .s_addr= *(u_int *) RTA_DATA(rtAttr);
break;
}
}
//printf("%s\n", inet_ntoa(rtInfo->dstAddr));
if (rtInfo->dstAddr.s_addr == 0)
sprintf(gateway, (char *) inet_ntoa(rtInfo->gateWay));
//printRoute(rtInfo);
return;
}
int main()
{
struct nlmsghdr *nlMsg;
struct rtmsg *rtMsg;
struct route_info *rtInfo;
char msgBuf[BUFSIZE];
int sock, len, msgSeq = 0;
/* Create Socket */
if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
perror("Socket Creation: ");
memset(msgBuf, 0, BUFSIZE);
/* point the header and the msg structure pointers into the buffer */
nlMsg = (struct nlmsghdr *) msgBuf;
rtMsg = (struct rtmsg *) NLMSG_DATA(nlMsg);
/* Fill in the nlmsg header*/
nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); // Length of message.
nlMsg->nlmsg_type = RTM_GETROUTE; // Get the routes from kernel routing table .
nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; // The message is a request for dump.
nlMsg->nlmsg_seq = msgSeq++; // Sequence of the message packet.
nlMsg->nlmsg_pid = getpid(); // PID of process sending the request.
/* Send the request */
if (send(sock, nlMsg, nlMsg->nlmsg_len, 0) < 0) {
printf("Write To Socket Failed...\n");
return -1;
}
/* Read the response */
if ((len = readNlSock(sock, msgBuf, msgSeq, getpid())) < 0) {
printf("Read From Socket Failed...\n");
return -1;
}
/* Parse and print the response */
rtInfo = (struct route_info *) malloc(sizeof(struct route_info));
//fprintf(stdout, "Destination\tGateway\tInterface\tSource\n");
for (; NLMSG_OK(nlMsg, len); nlMsg = NLMSG_NEXT(nlMsg, len)) {
memset(rtInfo, 0, sizeof(struct route_info));
parseRoutes(nlMsg, rtInfo);
}
free(rtInfo);
close(sock);
printGateway();
return 0;
}
Maybe this is very old question but I had same problem and I can't find better result. Finally I solved my problem with these code that it has a few changes. So I decide to share it.
char* GetGatewayForInterface(const char* interface)
{
char* gateway = NULL;
char cmd [1000] = {0x0};
sprintf(cmd,"route -n | grep %s | grep 'UG[ \t]' | awk '{print $2}'", interface);
FILE* fp = popen(cmd, "r");
char line[256]={0x0};
if(fgets(line, sizeof(line), fp) != NULL)
gateway = string(line);
pclose(fp);
}
I decided to go the "quick-and-dirty" way to start with and read out the ip from /proc/net/route using netstat -rm.
I thought I'd share my function... Note however that there is some error in it and prehaps you could help me find it and I'll edit this to be without faults. The function take a iface name like eth0 and returns the ip of the gateway used by that iface.
char* GetGatewayForInterface(const char* interface) {
char* gateway = NULL;
FILE* fp = popen("netstat -rn", "r");
char line[256]={0x0};
while(fgets(line, sizeof(line), fp) != NULL)
{
/*
* Get destination.
*/
char* destination;
destination = strndup(line, 15);
/*
* Extract iface to compare with the requested one
* todo: fix for iface names longer than eth0, eth1 etc
*/
char* iface;
iface = strndup(line + 73, 4);
// Find line with the gateway
if(strcmp("0.0.0.0 ", destination) == 0 && strcmp(iface, interface) == 0) {
// Extract gateway
gateway = strndup(line + 16, 15);
}
free(destination);
free(iface);
}
pclose(fp);
return gateway;
}
The problem with this function is that when I leave pclose in there it causes a memory corruption chrash. But it works if I remove the pclose call (but that would not be a good solution beacuse the stream would remain open.. hehe). So if anyone can spot the error I'll edit the function with the correct version. I'm no C guru and gets a bit confused about all the memory fiddling ;)