I'm completely new to netlink & co. and I am trying to establisch a connection from user space to the w1-kernel module of a raspberry pi.
Unfortunately the documentation i found is spotty and contradictory.
Here some of the things not clear to me:
basic communication is:
generate a socket: socket()
int s = socket(AF_NETLINK,SOCK_DGRAM, NETLINK_CONNECTOR);
bind it to a local name: bind()
int b = bind(s,(sockaddr*)&sa,sizeof(sa));
with
sa.nl_family=AF_NETLINK;
sa.nl_pid=getpid();//0?
sa.nl_groups=0; //23? -1?
create the message
send it: send()? sendmsg()?
wait for answer: poll()
read answer: recv()
+In examples i found (w1d.c and ucon.c) they use the send() command (not sendmsg) without a connect(), even though the man pages of send say that wouldnt work.
+I am not clear about the structure of the message:
send can send any buffer (char*)
netlink expects a struct nlmsghdr header;
connector expects a struct cn_msg header.
w1_netlink expects a w1_netlink_msg header and w1_netlink_cmd data.
Do i need all headers in a row? Ther are 2 sequence / message number variables, one in nlmsghdr and on in cn_msg???
The test program i wrote is not producing the result i expect: every thing works withour producing an error but i am getting no answer :-(
#include <iostream>
#include <linux/netlink.h>
#include <sys/types.h>
#include <sys/socket.h>
#include<sys/poll.h>
#include <unistd.h>
#include<cstring>
#include "w1_netlink.h"
__u32 nl_seq;
static int netlink_send(int s, struct cn_msg *msg) //copy from (ucon.c)
{
struct nlmsghdr *nlh;
unsigned int size;
int err;
char buf[128];
struct cn_msg *m;
size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
nlh = (struct nlmsghdr *)buf;
nlh->nlmsg_seq = nl_seq++;
nlh->nlmsg_pid = getpid();
nlh->nlmsg_type = NLMSG_DONE;
nlh->nlmsg_len = size;
nlh->nlmsg_flags = 0;
m = (cn_msg*) NLMSG_DATA(nlh);
memcpy(m, msg, sizeof(*m) + msg->len);
err = send(s, nlh, size, 0);
return err;
}
int main(int argc, char *argv[])
{
nl_seq=0;
int s = socket(AF_NETLINK,SOCK_DGRAM, NETLINK_CONNECTOR);
if(s==-1) {std::cout<<"no socket"; return s;};
std::cout<<"socket "<<s;
sockaddr_nl sa;
sa.nl_family=AF_NETLINK;
sa.nl_pid=0;//getpid();
sa.nl_groups=0;
int b = bind(s,(sockaddr*)&sa,sizeof(sa));
if(b==-1){std::cout<<"bind error";return b;}; //prints 3
std::cout<<"bind "<<b; //prints 0
int si=sizeof(struct cn_msg)+sizeof(struct w1_netlink_msg)+sizeof(w1_netlink_cmd);
char * buf;
buf=(char *)malloc(1024);
memset(buf,0,1024);
cn_msg *cnh = (cn_msg*)buf;
w1_netlink_msg* wnh=(w1_netlink_msg*)&cnh->data;
w1_netlink_cmd* wcmd = (w1_netlink_cmd*)&wnh->data;
cnh->id.idx=CN_W1_IDX;
cnh->id.val=CN_W1_VAL;
cnh->seq=nl_seq;
cnh->flags=0;
wnh->type=W1_LIST_MASTERS;
wnh->len=0;
cnh->len=sizeof(struct w1_netlink_msg)+sizeof(w1_netlink_cmd);
int len=netlink_send(s,cnh);
std::cout<<"send "<<len<<" "<<(int)wnh->status; //prints 52 0
pollfd pfd;
pfd.fd=s;
pfd.events=POLLIN;
pfd.revents=0;
int p=0;
while(p<1) {
p=poll(&pfd,1,1000);
std::cout<<"poll "<<p<<pfd.revents; //prints 0 0 in infinite loop
std::cout.flush();
};
memset(wcmd,0,128);
len=recv(s,buf,255,0);
std::cout<<"recv "<<len;
close(s);
return 0;
}
Result is socket 3 bind 0 send 52 0 poll 00 poll 00 ...
Thanks
Related
I want do a simple program, where a father process create some child processes; before child pause(), they notification father process.
Child processes run correctly, but father wait on select, otherwise child have written on socket; where is the mistake?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
typedef struct{
pid_t pid;
int sockfd;
}Child;
void err_exit(char* str)
{
perror(str);
exit(EXIT_FAILURE);
}
int convert_int(char* str)
{
int v;
char*p;
errno = 0;
v = strtol(str,&p,0);
if(errno != 0 || *p != '\0')
err_exit("errno");
return v;
}
void child_job(pid_t pid,int sockfd)
{
int v = write(sockfd,"1",1);
if(v == -1)
err_exit("write");
printf("process %d in pause()\n",pid);
pause();
}
int main(int argc, char* argv[])
{
int nsel;
fd_set masterset;
int n_child,i;
int sockfd[2];
pid_t pid;
Child* c = NULL;
if(argc != 2)
err_exit("usage: <awake2> #children\n");
FD_ZERO(&masterset);
n_child = convert_int(argv[1]);
c = malloc(n_child*sizeof(Child));
if(c == NULL)
err_exit("malloc");
for(i = 0; i <n_child; i++){
if ((socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd)) < 0) { //create socket between child and father
perror("errore in socketpair");
exit(1);
}
if ((pid = fork()) > 0) {
if (close(sockfd[1]) == -1) { //father process closes sockfd[1]
perror("errore in close");
exit(1);
}
c[i].pid = pid;
c[i].sockfd = sockfd[0];
FD_SET(c[i].sockfd, &masterset);
}
else if(!pid)
child_job(getpid(),c[i].sockfd);
}
for(;;){
if ((nsel = select(n_child+1, &masterset, NULL, NULL, NULL)) < 0) {
perror("errore in bind");
exit(1);
}
int i;
for(i = 0; i <n_child; i++){
if(FD_ISSET(c[i].sockfd, &masterset)) {
printf("changed fd\n");
}
}
}
}
One thing that's wrong is you're passing c[i].sockfd to child_job(). In the parent process, it was set to the first socket fd in the pair, but child_job() is called in the child process, where c never gets set to anything. You're passing the original contents of the malloc memory. Change that to child_job(getpid(), sockfd[1]); and you'll be getting closer.
Another thing is that the first argument to select is probably too low. n_child is the number of children, but you need to pass a number here that's greater than the highest file descriptor in your set. For example, run the program with the argument 1 so it creates 1 child. It is likely to start out with file descriptors 0, 1, and 2 open, so the socket pair will be file descriptors 3 and 4. The 3 goes into the fd_set, but the first argument to select is 1+1=2. select ignores your fd 3 because it's above the limit.
To fix that, create a new variable int maxfd; near your fd_set, initialize it to -1 when you FD_ZERO the set, and after every call to FD_SET, update it:
if( [whatever fd you just gave to FD_SET] > maxfd)
maxfd = [whatever fd you just gave to FD_SET];
and call select with maxfd+1 as the first argument.
(Or maybe switch to poll)
That should get you far enough that your first select call works. After that, you'll find more problems.
The fd_set you pass to select will be modified (that's why you can do FD_ISSET tests on it afterward). If you go back to the top of the loop and pass it again without reinitializing it, select will not be looking at all the file descriptors any more, just the ones that were ready in the first call. To fix this, make a second fd_set and copy the master into it just before the select call, and never pass the master to select. (Or you can rebuild the set from scratch each time by scanning the child table.)
If you get a readable fd from select, you should read it before calling select again, otherwise you're just in a "eat CPU calling select over and over" loop.
I am trying to understand an observation on behavior of select() when used on stdin, when it is receiving data from a pipe.
Basically I had a simple C program using the following code:
hello.c:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <termios.h>
int main(int argc, char *argv[])
{
int flags, opt;
int nsecs, tfnd;
fd_set rfds;
struct timeval tv;
int retval;
int stdin_fileno_p1 = STDIN_FILENO+1;
char c;
int n;
/* Turn off canonical processing on stdin*/
static struct termios oldt, newt;
tcgetattr( STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON);
tcsetattr( STDIN_FILENO, TCSANOW, &newt);
while (1)
{
FD_ZERO(&rfds);
FD_SET(STDIN_FILENO, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
retval = select(stdin_fileno_p1, &rfds, NULL, NULL, &tv);
if ( retval && (retval!=-1) )
{
n = read(STDIN_FILENO, &c, 1);
write(STDOUT_FILENO, &c, 1);
}
else printf("No Data\n");
usleep(100000);
}
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
}
If I ran the program as follows I could see characters echoing when I type keys on while the program is running. When keys are not pressed, it displays "No Data" as expected.
./hello
However, if use the program as follows, the program never gets to a state where is displays "No Data". Instead last character "c" is repeatedly displayed.
echo -n abc | ./hello
I'm a bit puzzled by this observation, and would be grateful if you could help me to understand the observed behavior.
The problem is that your program does not detect an end-of-file condition when it reads from the STDIN_FILENO descriptor. After echo has written the c character it will close its end of the pipe, which will cause the select in your program to return immediately and your read to return 0 as an indication that no more data will ever be available from that descriptor. Your program doesn't detect that condition. Instead it just calls write with whatever character was left in the buffer by the last successful read and then repeats the loop.
To fix, do if (n==0) break; after the read.
i have done simple tcp client/server program got working well with strings and character data...i wanted to take each frames(from a webcam) and sent it to server.. here is the part of client program where error happened:
line:66 if(send(sock, frame, sizeof(frame), 0)< 0)
error:
client.cpp:66:39: error: cannot convert ‘cv::Mat’ to ‘const void*’ for argument ‘2’ to ‘ssize_t send(int, const void*, size_t, int)
i cant recognise this error....kindly help...the following complete client program:
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include<stdlib.h>
#include<netdb.h>
#include<unistd.h>
#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc,char *argv[])
{
int sock;
struct sockaddr_in server;
struct hostent *hp;
char buff[1024];
VideoCapture capture;
Mat frame;
capture.open( 1 );
if ( ! capture.isOpened() ) { printf("--(!)Error opening video capture\n"); return -1; }
begin:
capture.read(frame);
if( frame.empty() )
{
printf(" --(!) No captured frame -- Break!");
goto end;
}
sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
perror("socket failed");
exit(1);
}
server.sin_family =AF_INET;
hp= gethostbyname(argv[1]);
if(hp == 0)
{
perror("get hostname failed");
close(sock);
exit(1);
}
memcpy(&server.sin_addr,hp->h_addr,hp->h_length);
server.sin_port = htons(5000);
if(connect(sock,(struct sockaddr *) &server, sizeof(server))<0)
{
perror("connect failed");
close(sock);
exit(1);
}
int c = waitKey(30);
if( (char)c == 27 ) { goto end; }
if(send(sock, frame, sizeof(frame), 0)< 0)
{
perror("send failed");
close(sock);
exit(1);
}
goto begin;
end:
printf("sent\n",);
close(sock);
return 0;
}
Because TCP provides a stream of bytes, before you can send something over a TCP socket, you must compose the exact bytes you want to send. Your use of sizeof is incorrect. The sizeof function tells you how many bytes are needed on your system to store the particular type. This bears no relationship to the number of bytes the data will require over the TCP connection which depends on the particular protocol layered on top of TCP you are implementing which must specify how data is to be sent at the byte level.
like david already said, you got the length wrong. sizeof() won't help, what you want is probably
frame.total() * frame.channels()
you can't send a Mat object, but you can send the pixels ( the data pointer ) , so this would be:
send(sock, frame.data,frame.total() * frame.channels(), 0)
but still a bad idea. sending uncompressed pixels over the netwotrk ? bahh.
please look at imencode/imdecode
i'm pretty sure, you got the client / server roles in reverse here.
usually the server holds the information to retrieve ( the webcam ), and the client connects to that
and requests an image.
As of title.
The program will wait for the first event, and then go into an infinite loop - why doesn't it just process one event at a time?
#include <stdio.h>
#include <stdlib.h>
#include <sys/inotify.h>
#include <unistd.h>
int main (int argc, char **argv)
{
int id, wd;
int a;
struct inotify_event e;
id = inotify_init ();
wd = inotify_add_watch (id, "/home/andrea/Downloads", IN_CREATE);
puts ("waiting...");
while (read (id, &e, sizeof (struct inotify_event)))
{
printf ("created %s\n", e.name);
puts ("waiting...");
}
return 0;
}
Firstly, the events reported by inotify aren't of the size inotify_event, since there is an additional name reported as well. Use ioctl with FIONREAD to get the amount of bytes available for reading.
int avail;
ioctl(id, FIONREAD, &avail);
Secondly, you used blocking I/O. If you instead use inotify_init1(O_NONBLOCK) to initialise inotify, read() will immediately return and set errno to EAGAIN if no data is available. Of course, this is optional if you first used FIONREAD to check if there is data available in the first place.
I have a unit test that checks behavior on blocking and non-blocking sockets - the server writes a long response and at some point it should not be able to write any more and it
blocks on write.
Basically one side writes and other side does not reads.
Under Solaris at some point I get a error "Not enough space" (after writing 75MB) instead of blocking on write:
Program that reproduces the problem:
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
char const *address = "127.0.0.1";
#define check(x) do { if( (x) < 0) { perror(#x) ; exit(1); } } while(0)
int main()
{
signal(SIGPIPE,SIG_IGN);
struct sockaddr_in inaddr = {};
inaddr.sin_family = AF_INET;
inaddr.sin_addr.s_addr = inet_addr(address);
inaddr.sin_port = htons(8080);
int res = fork();
if(res < 0) {
perror("fork");
exit(1);
}
if(res > 0) {
int fd = -1;
int status;
sleep(1);
check(fd = socket(AF_INET,SOCK_STREAM,0));
check(connect(fd,(sockaddr*)&inaddr,sizeof(inaddr)));
sleep(5);
close(fd);
wait(&status);
return 0;
}
else {
int acc,fd;
check(acc = socket(AF_INET,SOCK_STREAM,0));
int yes = 1;
check(setsockopt(acc,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)));
check(bind(acc,(sockaddr*)&inaddr,sizeof(inaddr)));
check(listen(acc,10));
check(fd = accept(acc,0,0));
char buf[1000];
long long total= 0;
do {
int r = send(fd,buf,sizeof(buf),0);
if(r < 0) {
printf("write %s\n",strerror(errno));
return 0;
}
else if(r==0) {
printf("Got eof\n");
return 0;
}
total += r;
if(total > 100*1024*1024) {
printf("Too much!!!!\n");
return 0;
}
printf("%lld\n",total);
}while(1);
}
return 0;
}
The output on Solaris (last two lines)
75768000
write Not enough space
The expected output on Linux (last two lines)
271760
write Connection reset by peer
Which happens only when the other side closes the socket.
Any ideas why and how can I fix it, what options to set?
P.S.: It is OpenSolaris 2009.06, x86
Edits
Added full C code that reproduces the problem
Answer:
This seems like a bug in specific version of Solaris kernel, libc library.
From OpenSolaris source code, I'm afraid the SO_SNDTIMEO option is unsupported: https://hg.java.net/hg/solaris~on-src/file/tip/usr/src/uts/common/inet/sockmods/socksctp.c#l1233
If you want to block if there's no space available, you need to write code to do that.
POSIX is pretty clear that write on a socket is equivalent to send with no options, and that send "may fail if ... [i]nsufficient resources were available in the system to perform the operation."