bind() picks zero port - linux

I am trying to write some socket app and got a problem. I want OS to pick random free port number for my address.
But I receive port number = 0. What am I doing wrong?
struct sockaddr_in addr;
socklen_t addrLen;
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1) {
ThreadError("Failed to create data channel socket");
}
addr.sin_family = AF_INET;
addr.sin_port = 0; // pick random free port
addr.sin_addr.s_addr = srvAddr; // = inet_addr(127.0.0.1)
if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
ThreadError("Failed to bind data channel");
}
if (getsockname(fd, (struct sockaddr *)&addr, &addrLen) == -1) {
ThreadError("getsockname() failed");
}
if (listen(fd, 1) == -1) {
ThreadError("Failed to set socket to listen mode");
}
// addr.sin_port == 0

You need to set addrlen = sizeof addr before you call getsockname.
The size is an in-out parameter. You specify the size of the buffer you're providing, and the function tells you how much of the buffer it used by modifying the size.

Related

Packet sniffer for link layer protocols

I am trying to convert a program called Responder which is written in Python to a C version. One of the spots I am stuck on is the listeners that listen on different ports. Responder listens for SMB on port 445 and 139. I created a small snippet that will listen on those ports as well. But when I run my program, I get no data.
void sniff(int PORT) {
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = {0};
if ((server_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == 0) {
return;
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
return;
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
return;
}
if (listen(server_fd, 3) < 0) {
return;
}
printf("listen done.\n");
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
return;
}
valread = read( server_fd , buffer, 1024);
printf("%s\n",buffer );
return;
}
If I do the above, I don't get anything.

Understandng the reason for recv blocking forever

I run a Linux program written in C that would periodically receive data by parsing an HTTP response, crunch some numbers and then report the result by HTTP GET of another web page.
My problem is that sometimes, one of the instances would "freeze".
Looking at top I can see that it is in sk_wait_data state and attaching a debugger reveals that it is blocked by a recv call.
Here is a minimal version of the code that does the TCP connection (it was adapted from http://www.linuxhowtos.org/C_C++/socket.htm):
int connectTCP(const char* host, const char* page, int portno) {
int sockfd;
struct sockaddr_in serv_addr;
struct hostent *server;
// Create socket //
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0)
error("ERROR opening socket");
// Get ip from hostname //
server = gethostbyname(host);
if (server == NULL)
error("ERROR, can not find host\n");
memset((char *) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
memcpy((char *)&serv_addr.sin_addr.s_addr, // Destination
(char *)server->h_addr, // Source
server->h_length); // Size
serv_addr.sin_port = htons(portno);
// Conect to socket //
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR connecting");
return sockfd;
}
char* httpGet(const char* host, const char* page, int portno) {
int sockfd, n;
sockfd = connectTCP(host, page, portno);
memset(buffer, 0, sizeof(buffer));
sprintf(buffer, "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n", page, host);
n = send(sockfd,buffer,strlen(buffer), 0);
if (n < 0)
error("ERROR writing to socket");
int count = 0;
do {
n = recv(sockfd, buffer + count, BUFFER_MAX_SIZE - count, 0);
if (n < 0) {
error("ERROR reading from socket");
}
count += n;
} while(n != 0);
close(sockfd);
return buffer;
}
Bugs in your code:
If recv() returns zero you whould close the socket and stop reading.
If recv() returns -1 you should report the error, close the socket, and stop reading, unless you had set a read timeout and errno was EAGAIN/EWOULDBLOCK, in which case you should handle the timeout however is appropriate for your application.

How can I print client sun_paths name at server side in PF_UNIX socket?

#define NAME "server"
main()
{
int sock, msgsock, rval;
int pid,len;
struct sockaddr_un server,clientv;
char bufRead[1024];
char bufWrite[1024];
unlink(NAME);
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0)
{
perror("opening stream socket");
exit(1);
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, NAME);
if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)))
{
perror("binding stream socket");
exit(1);
}
printf("Socket has name %s\n", server.sun_path);
listen(sock, 5);
msgsock = accept(sock, (struct sockaddr *)&clientv, &len);
if (msgsock == -1)
perror("accept");
printf("clientv add %s\n",clientv.sun_path);
}
but when I connect client gives the output:
Socket has name server
clientv add LK�ĿX�MK
accept() doesn't fill .sun_path in, so you need to get it manually using getsockname(). Should be something like:
struct sockaddr_storage storage;
socklen_t storage_len = sizeof(struct sockaddr_storage);
struct sockaddr_un *clientv = (struct sockaddr_un *)&storage;
if (0 == getsockname(sock, (struct sockaddr *)&clientv, &storage_len)) {
printf("clientv add %s\n", clientv.sun_path);
}

how to read/write from/to a SOCK_SEQPACKET socket?

I try to use a SOCK_SEQPACKET socket with this:
int rc, len;
int worker_sd, pass_sd;
char buffer[80];
struct iovec iov[1];
struct msghdr msg;
memset(&msg, 0, sizeof(msg));
memset(iov, 0, sizeof(iov));
iov[0].iov_base = buffer;
iov[0].iov_len = sizeof(buffer);
msg.msg_iov = iov;
msg.msg_iovlen = 1;
if((socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) < 0)
{
perror("server: socket");
exit -1;
}
memset(&server_address, 0, sizeof(server_address));
server_address.sun_family = AF_UNIX;
strcpy(server_address.sun_path, "/mysocket");
unlink("/mysocket");
if(bind(socket_fd, (const struct sockaddr *) &server_address, sizeof(server_address)) < 0)
{
close(socket_fd);
perror("server: bind error");
return 1;
}
while(1)
{
printf("wait for message\n");
bytes_received = recvmsg(socket_fd, &msg, MSG_WAITALL);
printf("%d bytes\n", bytes_received);
}
The problem is that the process does not wait but receives -1 from recvmsg and loops forever. Nowhere in the manpages is there any reference what functions shall be used with SOCK_SEQPACKET-style sockets, for example I am not really sure whether recvmsg is even the correct function.
SOCK_SEQPACKET is connection-orientated so you must first accept a connection then do your IO on the accepted client socket.
recvmsg() returns -1 when an error has occured - errno will be set to the error number.
Read here: http://pubs.opengroup.org/onlinepubs/009695399/functions/recvmsg.html

accept/epoll problem

I have this code that uses epoll and it has a problem. When I run it, it gives output:
Server-socket() is OK...
Server-bind() is OK...
3
4
accept: Invalid argument
I'm running it on ubuntu linux, system updated, both as limited user and root
what is wrong with the input to accept? What should I change?
struct epoll_event ev, events[MAX_EVENTS];
struct sockaddr_in serveraddr;
int listen_sock, conn_sock, nfds, epollfd;
int yes = 1;
/* Set up listening socket, 'listen_sock' (socket(),
bind(), listen()) */
if((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Server-socket() error lol!");
//just exit lol!
exit(1);
}
printf("Server-socket() is OK...\n");
//"address already in use" error message
/*if(setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("Server-setsockopt() error lol!");
exit(1);
}
printf("Server-setsockopt() is OK...\n");*/
// bind
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port = htons(PORT);
memset(&(serveraddr.sin_zero), '\0', 8);
if(bind(listen_sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1)
{
perror("Server-bind() error lol!");
exit(1);
}
printf("Server-bind() is OK...\n");
epollfd = epoll_create(MAX_EVENTS);
if (epollfd == -1) {
perror("epoll_create");
exit(EXIT_FAILURE);
}
ev.events = EPOLLIN;
ev.data.fd = listen_sock;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
perror("epoll_ctl: listen_sock");
exit(EXIT_FAILURE);
}
for (;;) {
nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
if (nfds == -1) {
perror("epoll_pwait");
exit(EXIT_FAILURE);
}
for (int n = 0; n < nfds; ++n) {
if (events[n].data.fd == listen_sock) {
struct sockaddr_in clientaddr;
socklen_t addrlen = sizeof(clientaddr);
cout <<listen_sock <<'\n' <<epollfd <<'\n';
conn_sock = accept(listen_sock, (struct sockaddr *) &clientaddr, &addrlen);
if (conn_sock == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
fcntl(conn_sock, F_SETFL, fcntl(conn_sock, F_GETFD, 0)|O_NONBLOCK);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = conn_sock;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
&ev) == -1) {
perror("epoll_ctl: conn_sock");
exit(EXIT_FAILURE);
}
} else {
printf("%d\n", events[n].data.fd);
}
}
}
You forgot to call listen() after bind():
listen(listen_sock, 5);
I built your source and had the same results. The epoll_wait returns immediately even though there is nothing to accept.
It appears to be the case that using epoll_wait instead of listen is not supported behavior.

Resources