I have this funny little problem in two nearly identical programs. What I am trying to do is send some data on Multicast socket and receive it. For now, I am okay if the sender receives the message (I'll set the option to not receive later).
I have two implementation cases. In the first approach, I am using the traditional way of initializing a sockaddr structure and then binding to, and also joining a multicast group on the same socket. This, however, is IPv4/IPv6 dependent and to circumvent that, I tried to use addrinfo structures in the second variant of the program. Both programs are given below.
The problem is, the messages are being received in the first use case, where I am using the regular sockaddr while, there is no message being received/socket descriptor being set in the second case. Could somebody help me out and explain why is this happening?
Variant 1 (with sockaddr)
#include<stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <fcntl.h> /* for nonblocking */
#include <netinet/tcp.h>
fd_set hm_tprt_conn_set;
main()
{
struct ip_mreq mreq;
struct sockaddr_in mc_addr;
int sock_fd ;
int val;
int reuse = 1;
struct sockaddr_in ip;
struct sockaddr_in src_addr;
int total_bytes_rcvd=0;
unsigned int length;
unsigned char buf[50];
int op_complete = 0;
int os_error;
struct timeval select_timeout;
fd_set read_set;
int32_t nready; //Number of ready descriptors
time_t time_val;
length = sizeof (src_addr);
sock_fd = socket(AF_INET, SOCK_DGRAM,0);
if(sock_fd == -1)
{
printf("\n Error Opening UDP MCAST socket");
perror("\n Cause is ");
exit(0);
}
printf("\n Setting the socket to non-blocking mode");
val = fcntl(sock_fd, F_GETFL , 0);
val = fcntl(sock_fd, F_SETFL, val | O_NONBLOCK);
if (val == -1)
{
printf("\n Error while setting socket to non-blocking mode");
perror("Cause is ");
sock_fd = -1;
exit(0);
} //end if val == -1
if (setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
{
fprintf(stderr, "setsockopt: %d\n", errno);
perror("Cause is ");
exit(0);
}
FD_SET(sock_fd, &hm_tprt_conn_set);
printf("\n Construct a mcast address structure");
/* construct a multicast address structure */
memset(&mc_addr, 0, sizeof(mc_addr));
mc_addr.sin_family = AF_INET;
mc_addr.sin_addr.s_addr = htonl(INADDR_ANY);
mc_addr.sin_port = htons(4936);
memset(&ip, 0, sizeof(ip));
ip.sin_family = AF_INET;
ip.sin_addr.s_addr = inet_addr("224.0.0.203")/*htonl(INADDR_ANY)*/;
ip.sin_port = htons(4936);
printf("\n Bind the multicast address structure and port to the recieving socket ");
if (bind( sock_fd, (struct sockaddr*) &mc_addr, sizeof(mc_addr)) == -1)
{
fprintf(stderr, "bind: %d\n", errno);
perror("\n Cause is ");
exit(0);
}
mreq.imr_multiaddr.s_addr = inet_addr("224.0.0.203");
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if(setsockopt(sock_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq, sizeof(mreq)) == -1)
{
fprintf(stderr, "setsockopt: %d\n", errno);
perror("\n Cause is ");
exit(0);
}
printf("\nCreated Recv Socket: %d", sock_fd);
fflush(stdout);
memset(&src_addr, 0, sizeof(mc_addr));
while(1){
/* Send a multicast */
time_val = time(NULL);
snprintf(buf, sizeof(buf), "Hello: %s", ctime(&time_val));
total_bytes_rcvd = sendto(sock_fd,
buf,
sizeof(buf),
0,
(struct sockaddr *)&ip,
length );
printf("\n%d bytes sent.", total_bytes_rcvd);
/* perform select */
select_timeout.tv_sec = 0;
select_timeout.tv_usec = 5000000;
read_set = hm_tprt_conn_set;
nready = select(sock_fd+1, &read_set, NULL, NULL, &select_timeout);
if(nready == 0)
{
/***************************************************************************/
/* No descriptors are ready */
/***************************************************************************/
continue;
}
else if(nready == -1)
{
perror("Error Occurred on select() call.");
continue;
}
if(FD_ISSET(sock_fd, &read_set))
{
printf("\n Recv the data");
total_bytes_rcvd = recvfrom(sock_fd,
buf,
sizeof(buf),
0,
(struct sockaddr *)&src_addr,
&length );
printf("%s: message = \" %s \"\n", inet_ntoa(src_addr.sin_addr), buf);
printf("\n total byte recieved %d", total_bytes_rcvd);
/***************************************************************************/
/* If select returned 1, and it was a listen socket, it makes sense to poll*/
/* again by breaking out and use select again. */
/***************************************************************************/
if(--nready <=0)
{
printf("\nNo more incoming requests.");
continue;
}
}//end select on listenfd
}
}
Variant 2 (with addrinfo)
#include<stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <fcntl.h> /* for nonblocking */
#include <netinet/tcp.h>
#include <netdb.h> /* AI_PASSIVE and other Macros for getaddrinfo() */
fd_set hm_tprt_conn_set;
main()
{
struct addrinfo hints, *res, *ressave;
char target[128] = "127.0.0.1";
char service[128] = "4936";
struct ip_mreq mreq;
int sock_fd ;
int val;
int reuse = 1;
struct sockaddr_in ip;
struct sockaddr_in src_addr;
int total_bytes_rcvd=0;
unsigned int length;
unsigned char buf[50];
int op_complete = 0;
int os_error;
struct timeval select_timeout;
fd_set read_set;
int32_t nready; //Number of ready descriptors
time_t time_val;
length = sizeof (src_addr);
sock_fd = socket(AF_INET, SOCK_DGRAM,0);
if(sock_fd == -1)
{
printf("\n Error Opening UDP MCAST socket");
perror("\n Cause is ");
exit(0);
}
printf("\n Setting the socket to non-blocking mode");
val = fcntl(sock_fd, F_GETFL , 0);
val = fcntl(sock_fd, F_SETFL, val | O_NONBLOCK);
if (val == -1)
{
printf("\n Error while setting socket to non-blocking mode");
perror("Cause is ");
sock_fd = -1;
exit(0);
} //end if val == -1
if (setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
{
fprintf(stderr, "setsockopt: %d\n", errno);
perror("Cause is ");
exit(0);
}
FD_SET(sock_fd, &hm_tprt_conn_set);
printf("\n Construct a mcast address structure");
/* construct a multicast address structure */
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
if((os_error = getaddrinfo(target, service, &hints, &res)) !=0)
{
printf("\n%s",gai_strerror(os_error));
exit(0);
}
ressave = res;
if(bind(sock_fd, res->ai_addr, res->ai_addrlen) != 0)
{
perror("Error binding to port");
close(sock_fd);
sock_fd = -1;
}
mreq.imr_multiaddr.s_addr = inet_addr("224.0.0.203");
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if(setsockopt(sock_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq, sizeof(mreq)) == -1)
{
fprintf(stderr, "setsockopt: %d\n", errno);
perror("Cause is ");
exit(0);
}
/* Set Destination address */
memset(&ip, 0, sizeof(ip));
ip.sin_family = AF_INET;
ip.sin_addr.s_addr = inet_addr("224.0.0.203")/*htonl(INADDR_ANY)*/;
ip.sin_port = htons(4936);
/* Set to zero address where addresses of sender will be received */
memset(&src_addr, 0, sizeof(src_addr));
while(1){
/* Send a multicast */
time_val = time(NULL);
snprintf(buf, sizeof(buf), "Hello: %s", ctime(&time_val));
total_bytes_rcvd = sendto(sock_fd,
buf,
sizeof(buf),
0,
(struct sockaddr *)&ip,
length );
printf("\n%d bytes sent.", total_bytes_rcvd);
/* perform select */
select_timeout.tv_sec = 0;
select_timeout.tv_usec = 5000000;
read_set = hm_tprt_conn_set;
nready = select(sock_fd+1, &read_set, NULL, NULL, &select_timeout);
if(nready == 0)
{
/***************************************************************************/
/* No descriptors are ready */
/***************************************************************************/
continue;
}
else if(nready == -1)
{
perror("Error Occurred on select() call.");
continue;
}
if(FD_ISSET(sock_fd, &read_set))
{
printf("\n Recv the data");
total_bytes_rcvd = recvfrom(sock_fd,
buf,
sizeof(buf),
0,
(struct sockaddr *)&src_addr,
&length );
printf("%s: message = \" %s \"\n", inet_ntoa(src_addr.sin_addr), buf);
printf("\n total byte recieved %d", total_bytes_rcvd);
/***************************************************************************/
/* If select returned 1, and it was a listen socket, it makes sense to poll*/
/* again by breaking out and use select again. */
/***************************************************************************/
if(--nready <=0)
{
printf("\nNo more incoming requests.");
continue;
}
}//end select on listenfd
}
}
The difference is that in the first variant you're binding to INADDR_ANY, while in the second variant you're binding to 127.0.0.1. Failing to bind to INADDR_ANY means you won't receive any multicast data.
You can fix this with the following:
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
if((os_error = getaddrinfo(NULL, service, &hints, &res)) !=0)
{
printf("\n%s",gai_strerror(os_error));
exit(0);
}
From the man page for getaddrinfo regarding AI_PASSIVE:
If node is NULL, the network address in each socket structure is initialized according to the AI_PASSIVE flag, which is set in
hints.ai_flags. The network address in each socket structure will be
left unspecified if AI_PASSIVE flag is set. This is used by server
applications, which intend to accept client connections on any network
address. The network address will be set to the loopback interface
address if the AI_PASSIVE flag is not set. This is used by client
applications, which intend to connect to a server running on the same
network host.
While in this case you are sending to the same host, multicast data does not go out on the localhost interface by default. You would need to call setsockopt with the IP_MULTICAST_IF option to set the outgoing multicast interface.
With this change, I was able to send and receive with the second variant.
Before you can bind() you need to have a working socket. You will need to cycle through all the results. Here's what's missing on your code.
ressave = res;
sock = socket(ressave->ai_family, ressave->ai_socktype, ressave->ai_protocol);
while(ressave != NULL && (sock < 0 || connect(sock, ressave->ai_addr, ressave->ai_addrlen) < 0)) {
close(sock);
if((ressave = ressave->ai_next) != NULL)
sock = socket(ressave->ai_family, ressave->ai_socktype, ressave->ai_protocol);
}
At this point you have either found a working socket sock or not. When ressave is not NULL then the value of socket sock is valid.
Related
Re-using code here to reproduce a tcp client/server interaction.
The server initializes fine, begins listening for connections.
However, on running client ./client, the client fails with message
connect(): Cannot assign requested address
where the "failing" code from the link above (and also pasted below) is:
ret = connect(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (ret == -1) {
perror("connect()");
close(sock_fd);
return EXIT_FAILURE;
}
When I run ifconfig, I do not see an IPv6 address. Is this a possible explanation? I am running an Ubuntu Docker image on an OSX machine.
The code is easily compilable/runnable with
gcc server.c -o server
gcc client.c -o client
./server
./client
server.c
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netinet/in.h>
#define CLIENT_QUEUE_LEN 10
#define SERVER_PORT 7002
int main(void)
{
int listen_sock_fd = -1, client_sock_fd = -1;
struct sockaddr_in6 server_addr, client_addr;
socklen_t client_addr_len;
char str_addr[INET6_ADDRSTRLEN];
int ret, flag;
char ch;
/* Create socket for listening (client requests) */
listen_sock_fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if(listen_sock_fd == -1) {
perror("socket()");
return EXIT_FAILURE;
}
/* Set socket to reuse address */
flag = 1;
ret = setsockopt(listen_sock_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
if(ret == -1) {
perror("setsockopt()");
return EXIT_FAILURE;
}
server_addr.sin6_family = AF_INET6;
server_addr.sin6_addr = in6addr_any;
server_addr.sin6_port = htons(SERVER_PORT);
/* Bind address and socket together */
ret = bind(listen_sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
if(ret == -1) {
perror("bind()");
close(listen_sock_fd);
return EXIT_FAILURE;
}
/* Create listening queue (client requests) */
ret = listen(listen_sock_fd, CLIENT_QUEUE_LEN);
if (ret == -1) {
perror("listen()");
close(listen_sock_fd);
return EXIT_FAILURE;
}
client_addr_len = sizeof(client_addr);
while(1) {
/* Do TCP handshake with client */
client_sock_fd = accept(listen_sock_fd,
(struct sockaddr*)&client_addr,
&client_addr_len);
if (client_sock_fd == -1) {
perror("accept()");
close(listen_sock_fd);
return EXIT_FAILURE;
}
inet_ntop(AF_INET6, &(client_addr.sin6_addr),
str_addr, sizeof(str_addr));
printf("New connection from: %s:%d ...\n",
str_addr,
ntohs(client_addr.sin6_port));
/* Wait for data from client */
ret = read(client_sock_fd, &ch, 1);
if (ret == -1) {
perror("read()");
close(client_sock_fd);
continue;
}
/* Do very useful thing with received data :-) */
ch++;
/* Send response to client */
ret = write(client_sock_fd, &ch, 1);
if (ret == -1) {
perror("write()");
close(client_sock_fd);
continue;
}
/* Do TCP teardown */
ret = close(client_sock_fd);
if (ret == -1) {
perror("close()");
client_sock_fd = -1;
}
printf("Connection closed\n");
}
return EXIT_SUCCESS;
}
client.c
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#define SERVER_PORT 7002
int main(int argc, char *argv[])
{
int sock_fd = -1;
struct sockaddr_in6 server_addr;
int ret;
char ch = 'a';
/* Arguments could be used in getaddrinfo() to get e.g. IP of server */
(void)argc;
(void)argv;
/* Create socket for communication with server */
sock_fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (sock_fd == -1) {
perror("socket()");
return EXIT_FAILURE;
}
/* Connect to server running on localhost */
server_addr.sin6_family = AF_INET6;
inet_pton(AF_INET6, "::1", &server_addr.sin6_addr);
server_addr.sin6_port = htons(SERVER_PORT);
/* Try to do TCP handshake with server */
ret = connect(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (ret == -1) {
perror("connect()");
close(sock_fd);
return EXIT_FAILURE;
}
/* Send data to server */
ret = write(sock_fd, &ch, 1);
if (ret == -1) {
perror("write");
close(sock_fd);
return EXIT_FAILURE;
}
/* Wait for data from server */
ret = read(sock_fd, &ch, 1);
if (ret == -1) {
perror("read()");
close(sock_fd);
return EXIT_FAILURE;
}
printf("Received %c from server\n", ch);
/* DO TCP teardown */
ret = close(sock_fd);
if (ret == -1) {
perror("close()");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
So when I ran the code on a non docker container (the host) which has an IPv6 address based on running ifconfig, I get the output
Received b from server
which appears to confirm my suspicion that the container does not support IPv6.
If anyone cares to elaborate, they are welcome to.
Your server_addr.sin6_flowspec and other members of that struct are being left uninitialized.
Start by zero'ing out your server_addr instances before passing it to connect.
Either this at declaration time:
struct sockaddr_in6 server_addr = {0};
Or a memset call to fill it with all zeros before you start assigning the members of that struct values.
memset(&server_addr, '\0', sizeof(server_addr));
I believe that will fix your issue. If not, read on.
If the above doesn't resolve your issue, it's likely because you aren't properly initializing the sin6_flowspec or other members of the sockaddr_in6 struct that aren't in the ipv4 sockaddr_in struct. You can leverage getaddrinfo to do the heavy work for you to properly fill in these fields.
int result = 0;
addrinfo* resultList = NULL;
addrinfo hints = {};
hints.ai_family = AF_INET6;
hints.ai_flags |= AI_NUMERICHOST; // comment this line out if getaddrinfo fails
hints.ai_socktype = SOCK_STREAM;
int result = getaddrinfo("::1", NULL, &hints, &resultList);
if ((result == 0) && (resultList->ai_family == AF_INET6))
{
memcpy(&server_addr, resultList->ai_addr, sizeof(sockaddr_in6));
server_addr.sin6_port = htons(SERVER_PORT);
}
else
{
// fail
}
if (resultList)
{
freeaddrinfo(&resultList);
}
resultList = NULL;
My Server can handle multiple clients/switches at a time.
My problem is in my switch I believe, I'm trying to send an open message to the the controller. I create the the tcp socket in the switch and then right after I try to send the message to the controller, however when I try to do this, the socket disconnects from the controller and goes into an infinite loop. I'm not sure why this occurs as I'm creating and sending the message outside of my while loop. If I comment where I send the message, the socket stays connected to the controller and I am able to wait for one of a set of file descriptors to become ready to perform I/O, currently I only have the keyboard and the socket. My socket also receives a message from the controller when it's connected "You are connected to the server". In addition since my switch socket disconnects my recv() return error code 107 due to the fact the socket is disconnected.
I'm not sure If I provided too much code to look through but I added comments where I thought my error was occurring in the switch as well as the controller. Greatly appreciated for some help. I didn't add any of my own header files because they are not necessary.
This where I execute the switch. Sends and receive messages here.
#include "switch.h"
#include "openFIFO.h"
#include "packets.h"
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<poll.h>
#include <signal.h>
void do_switch(int swIport, char *trafficfile,int swJport, int swKport, int IPlow, int IPhigh,char serverAddress[256], unsigned short portNumber){
int switch_sock;
char server_response[256];
struct pollfd pfds[6];
int rval;
/* Switch */
Switch sw;
sw.swJport = swJport;
sw.swIport = swIport;
sw.swKport = swKport;
sw.IPlow = IPlow;
sw.IPhigh = IPhigh;
int switchLength = sizeof(Switch);
// printf("\n\nstruct switchLength: %d\n", switchLength);
// printf("\n\nSwitch Struct: swIport: %d, swJport: %d, swKport: %d,
IPlow: %d, IPhigh: %d\n", sw.swIport, sw.swJport, sw.swKport, sw.IPlow,
sw.IPhigh);
printf("\n\nSwitch created with the following: swIport: %d, trafficfile:
%s, swJport: %d, swKport: %d, IPlow: %d, IPhigh: %d, serverAddress: %s,
portNumber: %d\n", swIport, trafficfile, swJport, swKport, IPlow, IPhigh,
serverAddress, portNumber);
int fifoWrite[2];
int fifoRead[2];
int counter = 0;
char message[20] = "Hello";
/* Create fifos */
if(swJport != -1){
fifoWrite[0] = openWF(swIport,swJport);
fifoRead[0] = openReadFifo(swJport, swIport);
counter = counter + 2;
}
if(swKport != -1){
fifoWrite[1] = openWF(swIport,swKport);
fifoRead[1] = openReadFifo(swKport, swIport);
counter = counter + 2;
}else if(swKport == -1){
fifoWrite[0] = openWF(swIport,swKport);
fifoRead[0] = openReadFifo(swKport, swIport);
counter = counter + 2;
}
printf("fifoWrite[0]: %d\n", fifoWrite[0]);
printf("fifoRead[0]: %d\n", fifoRead[0]);
printf("fifoWrite[1]: %d\n", fifoWrite[1]);
printf("fifoRead[1]: %d\n", fifoRead[1]);
/* Establish connection between the controller and switch */
/* Send a open packet to the controller */
/* Sending a stuct */
//PROBELM HERE BELOW!!!!!!!
switch_sock = CreateTCPClientSocket(portNumber, serverAddress);
if(send(switch_sock, message, sizeof(message), 0) == -1){
fprintf(stderr, "Send() Failed");
}
else{
printf("Open packet is being sent to the controller\n");
}
/* Initialize poll parameters */
//Keyboard
pfds[0].fd = STDIN_FILENO;
pfds[0].events = POLLIN;
// Socket!
pfds[1].fd = switch_sock;
pfds[1].events = POLLIN;
printf("Starting switch............................\n\n");
while(1){
rval = poll(pfds,2,-1);
if(rval == 0){
fprintf(stderr, "Poll timed out. \n");
}if(rval == -1){
fprintf(stderr, "ERROR: poll() failed");
exit(0);
}
/* Check Keyboard */
if(pfds[0].revents & POLLIN && pfds[0].fd == 0){
int a;
char command[1024][256];
int commands;
char buf[256];
commands = read(0, buf, 256);
buf[commands] = '\0';
buf[commands] = '\0';
char *token;
token = strtok(buf, " ");
while(token != NULL){
strcpy(command[a], token);
a++;
token = strtok(NULL, " ");
}
a = 0;
bzero(buf, 256);
if(strcmp(command[0], "list") == 0){
//TODO: Make a print function
printf("print_switch()\n");
}
if(strcmp(command[0], "exit") == 0){
//TODO: Make a print function
printf(" print_switch()\n");
printf("switch-disconnected\n");
close(switch_sock);
exit(0)
}
}
/* Server sent a welcome message */
// Might be PROBELM HERE BELOW when trying to send the initial packet to
controller!!!!!!!
if(pfds[1].revents & POLLIN){
recv(switch_sock, &server_response, sizeof(server_response), 0);
printf("%s\n", server_response);
}
}
}
Creates a TCP Socket for the switch.
int CreateTCPClientSocket( unsigned short port, char *serverAddress){
int sock; /*socket to create */
struct sockaddr_in servAddr; /* Local address */
/* Construct local address structure */
/* Create socket for incoming connections */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){
fprintf(stderr,"ERROR: socket() failed\n");
exit(0);
}
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(port);
servAddr.sin_addr.s_addr = inet_addr(serverAddress);
if(connect(sock, (struct sockaddr *)&servAddr, sizeof(struct sockaddr)) <
0){
printf("Error code: %d\n", errno);
fprintf(stderr, "ERROR: connect() just failed\n");
exit(0);
}
return sock;
}
This is the controller
#include "controller.h"
#include "packets.h"
#include "switch.h"
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void do_controller(int nSwitch, int portNumber){
int controller_sock; /* Socket descriptor for server/controller */
int clnSocket; /*Socket descriptor for clients */
int activity;
int max_sd;
int sd;
int client_socket[nSwitch];
struct sockaddr_in address;
int addrlen;
/* Controller stuff */
Controller cont;
cont.ackCounter = 0;
cont.openCounter = 0;
Switch sw;
char message[256] = "You have reached the server\n";
char recv_message[20];
printf("\n\nController created: nSwitch: %d on portNumber: %d\n", nSwitch, portNumber);
/* Initialise all client_socket[] to 0 so not checked */
for(int i = 0; i < nSwitch; i++){
client_socket[i] = 0;
}
/*Create the server/controller socket */
controller_sock = CreateTCPServerSocket(portNumber);
//addrlen = sizeof(address);
/* Prepare for nonblocking I/O polling/select from the controller socket */
printf("Starting server.........\n\n");
while(1){
/* Zero the socket set and set for server sockets */
/* This must be reset every time select() is called */
/* Add keyboard to descriptor */
/* Add client and controller sockets to set */
FD_ZERO(&sockSet);
FD_SET(STDIN_FILENO, &sockSet);
FD_SET(controller_sock, &sockSet);
max_sd = controller_sock;
//max_sd = 0;
printf("nSwitch: %d\n", nSwitch);
for(int x = 0; x < nSwitch; x++){
sd = client_socket[x];
printf("sd: %d\n\n", sd);
if(sd > 0)
FD_SET(sd, &sockSet);
if(sd > max_sd)
max_sd = sd;
}
printf("max_sd: %d\n", max_sd);
//wait for one of the sockets, timeout is Null,
//so wait indefinitely
activity = select(max_sd + 1, &sockSet, NULL, NULL,NULL);
//printf("Activity: %d\n", activity);
if(activity < 0){
fprintf(stderr, "ERROR: select()\n");
exit(0);
}
/*Check keyboard */
if(FD_ISSET(STDIN_FILENO, &sockSet)){
int a;
char command[1024][256];
int commands;
char buf[256];
commands = read(0, buf, 256);
buf[commands] = '\0';
char *token;
token = strtok(buf, " ");
while(token != NULL){
strcpy(command[a], token);
a++;
token = strtok(NULL, " ");
}
a = 0;
bzero(buf, 256);
if(strcmp(command[0], "list") == 0){
//TODO: Make a print function
print_controller(&cont, nSwitch);
}
if(strcmp(command[0], "exit") == 0){
//TODO: Make a print function
print_controller(&cont, nSwitch);
exit(0);
}
continue;
}
/* Check the incoming FIFOS from the controller an attached switches */
/*If something happened on the controller socket,
then its an incomming connection. Accept new communitcation.Wait for a client to connect.
Recieve packets sent to the controller_sock
*/
if(FD_ISSET(controller_sock, &sockSet)){
clnSocket = AcceptTCPConnection(controller_sock);
if(send(clnSocket, message, sizeof(message), 0) != sizeof(message)){
fprintf(stderr, "Send()");
exit(0);
}
puts("Welcome message sent successfuly");
//PROBELM HERE BELOW!!!!!!! Returns error code 107 because the
socket disconnected.
recv(controller_sock, &recv_message, sizeof(recv_message), 0);
printf("This is my recv_message: %s\n", recv_message);
/*add new socket to array of sockets*/
for(int a = 0; a < nSwitch; a++){
/*if position is empty */
if(client_socket[a] == 0){
client_socket[a] = clnSocket;
printf("Adding to list of sockets as %d\n", client_socket[a]);
break;
}
}
}
/* Communicate with the sockets and handle TCP Client */
for(int z = 0; z <nSwitch; z++){
sd = client_socket[z];
/*Check if it was socket closed, and do other stuff */
if(FD_ISSET(sd ,&sockSet )){
getpeername(sd , (struct sockaddr*)&address , (socklen_t*)&addrlen);
printf("Host disconnected , ip %s , port %d \n" , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
close( sd );
client_socket[z] = 0;
}else{
//Do stuff for the client
printf("This is the client %d\n", sd);
}
}
}
}
These are the controllers functions: Assign a port to socket,Set socket to listen
int AcceptTCPConnection(int servSock){
int clntSock; /* Socket descriptor for client */
unsigned int clientAddressLen; /* sizeof(client_address); Length of client */
struct sockaddr_in cli_addr; /* Client address */
/* Set the size of the in-out parameter */
clientAddressLen = sizeof(cli_addr);
printf("ClientAddressLen: %x\n", clientAddressLen);
/* Wait for a client to connect */
if ((clntSock = accept(servSock, (struct sockaddr *) &cli_addr,
&clientAddressLen)) < 0){
fprintf(stderr, "ERROR: accept failed\n");
exit(0);
}
/* clntSock is connected to a client! */
//infrom user of socket number used in send and receive commands
printf("Handling client %s\n", inet_ntoa(cli_addr.sin_addr));
printf("New connection: socket fd is: %d, ip is: %s, port: %d\n\n",
clntSock, inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
return clntSock;
}
Create a TCP socket
int CreateTCPServerSocket(unsigned short port){
int sock; /* socket to create */
struct sockaddr_in servAddr; /* Local address */
/* Create socket for incoming connections */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){
fprintf(stderr,"ERROR: socket() failed\n");
exit(0);
}
/* Construct local address structure */
/* Define the server address */
//bzero((char *) &server_address, sizeof(server_address));
memset(&servAddr, 0, sizeof(servAddr)); /* Zero out structure */
servAddr.sin_family = AF_INET; /* Internet address family
*/
servAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface
*/
servAddr.sin_port = htons(port); /* Local port */
/* Bind to the local address */
printf("New connection: ip is: %s, port: %d\n\n",
inet_ntoa(servAddr.sin_addr), ntohs(servAddr.sin_port));
if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0){
printf("Error code: %d\n", errno);
fprintf(stderr,"ERROR: bind() just failed\n");
exit(0);
}
/* Mark the socket so it will listen for incoming connections */
if (listen(sock, 5) < 0){
fprintf(stderr,"ERROR: listen() failed\n");
exit(0);
}
return sock;
}
I am trying to create a portscanner in c. If the port is open, I want to get a response from the server. When I use regular blocking sockets, this works fine. For example, I know that for a certain address on my network, if I check port 80, it will return the html page to me when I call recv. I have tested this, and it works correctly every time.
However, I want to use nonblocking sockets, because sometimes certain servers will not respond and will cause the program to hang. I was able to get the nonblocking sockets to (kindof) work (the code is currently commented out below). I could see which ports were open, which were closed, and which timed out, but I was not able to get a response from the server (even though I know it should send one). What am I doing wrong?
tl;dr: When using nonblocking sockets (vs blocking), recv doesn't return any data.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <fcntl.h>
#define MAX_LEN 100000
int main(int argc, char **argv)
{
int sock, test_sock;
struct sockaddr_in server_addr;
struct hostent *hp;
char buf[MAX_LEN];
int num_bytes;
int err_code;
int START_PORT = 1;
int END_PORT = 100;
fd_set fdset;
struct timeval tv;
int opts;
// resolve server name for its IP address, etc.
hp = gethostbyname(argv[1]);
if (NULL == hp) {
perror("gethostbyname");
exit(2);
}
//printf("Here1\n");
// build remote server addr/port
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
//server_addr.sin_port = htons(atoi(argv[2]));
test_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
for(int i=START_PORT; i<=END_PORT; i++) {
printf("Here2\n");
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //created the tcp socket
//opts = fcntl(sock, F_SETFL, O_NONBLOCK);
printf("Here3\n");
if (sock < 0)
{
perror("Socket()\n");
exit(1);
}
server_addr.sin_port = htons(i);
// connect to server
printf("Here4\n");
err_code = connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
printf("Here5\n");
/* ... */
if (err_code < 0) {
printf("Port %d: connection refused\n", i);
//exit(3);
} else {
printf("Port %d:\n", i);
memset(buf, 0, MAX_LEN);
// Create message to send
char message[256];
strcpy(message, "GET / HTTP/1.0\r\nHost: ");
strcat(message, argv[1]);
strcat(message, "\r\n\r\n");
unsigned total_bytes_sent = 0;
num_bytes = send(sock, message, strlen(message), 0);
if (num_bytes < 0) {
perror("send");
exit(4);
}
unsigned total_bytes_received = 0;
while(1) {
num_bytes = recv(sock, buf+total_bytes_received, MAX_LEN, 0);
if(num_bytes <= 0){
break;
}
total_bytes_received += num_bytes;
}
// display received ack message
//printf("Port %d:\n", i);
fflush(stdout);
write(1, buf, total_bytes_received);
printf("\n");
printf("Done...\n");
}
close(sock);
}
// close sock to release resource
close(sock);
return 0;
}
SOLUTION
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#define MAX_LEN 100000
int main(int argc, char **argv)
{
int sock, sock_test;
struct sockaddr_in server_addr;
struct hostent *hp;
char buf[MAX_LEN];
int num_bytes;
int err_code;
int START_PORT = 1;
int END_PORT = 100;
int valid = 1;
fd_set fdset;
struct timeval tv;
// resolve server name for its IP address, etc.
hp = gethostbyname(argv[1]);
if (NULL == hp) {
perror("gethostbyname");
exit(2);
}
// build remote server addr/port
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
for(int i=START_PORT; i<=END_PORT; i++) {
sock_test = socket(AF_INET, SOCK_STREAM, 0);
if (sock_test < 0)
{
perror("Socket()\n");
exit(1);
}
fcntl(sock_test, F_SETFL, O_NONBLOCK);
server_addr.sin_port = htons(i);
connect(sock_test, (struct sockaddr *)&server_addr, sizeof(server_addr));
FD_ZERO(&fdset);
FD_SET(sock_test, &fdset);
tv.tv_sec = 3;
tv.tv_usec = 0;
if (select(sock_test + 1, NULL, &fdset, NULL, &tv) == 1)
{
int so_error;
socklen_t len = sizeof so_error;
getsockopt(sock_test, SOL_SOCKET, SO_ERROR, &so_error, &len);
if (so_error == 0) {
printf("%s:%d is open\n", argv[1], i);
memset(buf, 0, MAX_LEN);
// Create message to send
char message[256];
strcpy(message, "GET / HTTP/1.0\r\nHost: ");
strcat(message, argv[1]);
strcat(message, "\r\n\r\n");
printf("Here6\n");
unsigned total_bytes_sent = 0;
num_bytes = send(sock_test, message, strlen(message), 0);
printf("Here7\n");
int retry = 3;
unsigned total_bytes_received = 0;
while(retry) {
num_bytes = recv(sock_test, buf+total_bytes_received, MAX_LEN, 0);
if (0 == num_bytes)
{
/* socket has been closed by peer */
break;
}
else if(-1 == num_bytes)
{
if ((EAGAIN == errno) || (EWOULDBLOCK == errno))
{
/* no data to be read on socket */
retry--;
/* wait one second */
sleep(1);
}
else
{
/* other error */
perror("recv");
break;
}
}
else
{
total_bytes_received += num_bytes;
}
}
// display received ack message
//printf("Port %d:\n", i);
fflush(stdout);
write(1, buf, total_bytes_received);
printf("\n");
printf("Done...\n");
}
else
{
//printf("%s:%d is closed\n", argv[1], i);
}
} else {
printf("timed out\n");
valid = 0; //set the boolean flag to false
}
close(sock_test);
}
// close sock to release resource
close(sock_test);
return 0;
}
As pointed in comments, in non-blocking mode, you have to handle cases when
server is not ready to send data.
For man recv(3)
Return Value
Upon successful completion, recv() shall return the length of the message in bytes. If no messages are available to be received and the peer has performed an orderly shutdown, recv() shall return 0. Otherwise, -1 shall be returned and errno set to indicate the error.
Errors
The recv() function shall fail if:
EAGAIN or EWOULDBLOCK
The socket's file descriptor is marked O_NONBLOCK and no data is waiting to be received; or MSG_OOB is set and no out-of-band data is available and either the socket's file descriptor is marked O_NONBLOCK or the socket does not support blocking to await out-of-band data.
Since your client may try to read before the server send something, you must
adapt your code to wait:
/* maximum number of retry, one second per retry */
int retry = 10;
unsigned total_bytes_received = 0;
while(retry) {
num_bytes = recv(sock, buf+total_bytes_received, MAX_LEN, 0);
if (0 == num_bytes)
{
/* socket has been closed by peer */
break;
}
else if(-1 == num_bytes)
{
if ((EAGAIN == errno) || (EWOULDBLOCK == errno))
{
/* no data to be read on socket */
retry--;
/* wait one second */
sleep(1);
}
else
{
/* other error */
perror("recv");
break;
}
}
else
{
total_bytes_received += num_bytes;
}
}
I have been trying to learn sockets programming, and came across this website: http://beej.us/guide/bgnet/output/html/multipage/index.html which is really good. I was able to understand, but after writing a test program myself I ended up with a problem which I cannot figure after 3 hours. Have very limited time, so thought asking experts help here.
This is my server program:
/**
* Program showing how sockets can be used
*/
#include <stdio.h> // For printf
#include <strings.h> // For bzero, memset
#include <stdlib.h> // For exit, atoi
#include <unistd.h> // For close
#include <sys/socket.h> // For socket
#include <sys/types.h> // For types
#include <arpa/inet.h> // For inet_addr
#include <netdb.h> // Import module network database
#include <errno.h> // To access the global errno that holds last system call error
#include <assert.h> // For asserting
#define ADDRESSINFO_GET_SUCCESS 0
const int kSuccess = 0;
const char *kMyPort = "3490"; // Can be either port num or name of the service
const int kMaxListenConn = 10; // How many connections queue will hold
// Utility function to get socket address, IPv4 or IPv6:
void* getSocketAddress(const struct sockaddr *sa)
{
// Cast socketaddr to sockaddr_in to get address and port values from data
if (sa->sa_family == PF_INET) {
return &(((struct sockaddr_in *)sa)->sin_addr);
}
return &(((struct sockaddr_in6 *)sa)->sin6_addr);
}
// Utility function to get socket address string
void getSocketAddressString(const struct sockaddr *sd, char *ipAddr)
{
inet_ntop(sd->sa_family, getSocketAddress(sd), ipAddr, INET6_ADDRSTRLEN);
}
int createAndBindSocket(const struct addrinfo *addrList)
{
int status = -1; // Invalid status
int socketFileDesc = -1; // Invalid descriptor
const struct addrinfo *addrIt;
/*
* STEP 2.1: Loop through all the addrinfo nodes and bind to the one we can
*/
for (addrIt = addrList; addrIt != NULL; addrIt = addrIt->ai_next)
{
char ipAddr[INET6_ADDRSTRLEN];
inet_ntop(addrIt->ai_family, getSocketAddress(addrIt->ai_addr), ipAddr, sizeof ipAddr);
printf("IP: %s\n", ipAddr);
/*
* STEP 2.2: Crete the socket file descriptor for our IP address
*/
socketFileDesc = socket(addrIt->ai_family, addrIt->ai_socktype, addrIt->ai_protocol);
if (socketFileDesc == -1) {
fprintf(stderr, "Failed to create socket with error: %d\n", errno);
perror("socket"); // Get error desc
continue; // Try next address
}
/*
* STEP 2.3: Set socket behaviour by making ip address to be re-used if used already
*/
int yes=1;
if (setsockopt(socketFileDesc, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("setsockopt");
exit(1);
}
printf("Port %d\n",((struct sockaddr_in *)addrIt->ai_addr)->sin_port);
/*
* STEP 2.4: Bind our socket with ip address and port number to listen
*/
status = bind(socketFileDesc, addrIt->ai_addr, addrIt->ai_addrlen);
if (status != kSuccess) {
fprintf(stderr, "Failed to bind socket with error:%d\n", errno);
perror("bind"); // Get error desc
// Clear socket
close(socketFileDesc);
socketFileDesc = -1;
continue; // Try next address
}
}
return socketFileDesc;
}
int main()
{
int status = -1; // Status is invalid
struct addrinfo hints; // Holds our hints to get address info
struct addrinfo *addrList; // Contains our address info
/*
* STEP 1: Setup service details
*/
// Make sure struct is empty
bzero(&hints, sizeof hints); // memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; // Don't care IPv4 or v6
hints.ai_socktype = SOCK_STREAM; // Use TCP stream sockets
hints.ai_flags = AI_PASSIVE; // Use my local IPs or you igore this and provide IP manually in first arg
status = getaddrinfo(NULL, kMyPort, &hints, &addrList);
if (status != kSuccess) {
fprintf(stderr, "Failed to get address info with error: %s\n", gai_strerror(status));
exit(1);
}
/*
* STEP 2: Create a socket and bind it
*/
int socketFileDesc;
socketFileDesc = createAndBindSocket(addrList);
freeaddrinfo(addrList); // Done with list
if (socketFileDesc == -1) {
exit(1);
}
/*
* STEP 3: Listen to the port for incoming connections
*/
status = listen(socketFileDesc, kMaxListenConn); // Second arg is number of incoming connections in queue
if (status != kSuccess) {
fprintf(stderr, "Failed to listen to the port\n");
perror("listen");
goto exit;
}
printf("Server is listening at the port %s\n", kMyPort);
struct sockaddr_storage inConnAddr; // Big enough to hold both IPv4 and v6
socklen_t inConnAddrLen = sizeof inConnAddr;
const size_t kMaxBufferSize = 50;
char buff[kMaxBufferSize] = {0};
long bytesReceived = -1;
long bytesSent = 0;
int clientSockfd;
while (1) {
/*
* STEP 4: Accept incoming connections
*/
inConnAddrLen = sizeof inConnAddr;
clientSockfd = accept(socketFileDesc, (struct sockaddr *)&inConnAddr, &inConnAddrLen);
// Got new connection ?
if (clientSockfd == -1) {
perror("accept"); // Print error description
continue; // Continue to look for new connections
}
//
// Got connection, create child process to handle request
//
if (!fork()) {
close(socketFileDesc); // No need with child
char ipAddr[INET6_ADDRSTRLEN];
getSocketAddressString((struct sockaddr *)&inConnAddr, ipAddr);
printf("Child process created for hanlding request from %s\n", ipAddr);
/*
* STEP 5: Receive and Send data to requests
*/
bytesReceived = recv(clientSockfd, &buff, kMaxBufferSize - 1, 0);
if (bytesReceived > 0)
{
printf("Data from client %s\n", buff);
while (bytesSent < bytesReceived) {
bytesSent = send(clientSockfd, buff, bytesReceived, 0);
printf("Bytes sent %ld\n", bytesSent);
}
}
if (bytesReceived < 0) {
perror("recv");
}
else if (bytesReceived == 0) {
printf("Connection closed by server\n");
}
close(clientSockfd); // Close socket
exit(0);
}
}
exit:
/*
* STEP 5: Close the socket
*/
close(socketFileDesc);
return 0;
}
This is my client program:
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#include <strings.h>
#include <arpa/inet.h>
const char kSuccess = 0;
// Utility function to get socket address
void* getSocketAddress(const struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &( ((struct sockaddr_in *)sa)->sin_addr );
}
return &( ((struct sockaddr_in6 *)sa)->sin6_addr );
}
// Utility function to get socket address string
void getSocketAddressString(const struct sockaddr *sd, char *ipAddr)
{
inet_ntop(sd->sa_family, getSocketAddress(sd), ipAddr, INET6_ADDRSTRLEN);
}
int createAndConnectSocket(const struct addrinfo *addrList)
{
int socketFileDesc = -1; // Invalid descriptor
const struct addrinfo *addrIt;
/*
* STEP 2.1: Loop through all the addrinfo nodes and bind to the one we can
*/
for (addrIt = addrList; addrIt != NULL; addrIt = addrIt->ai_next)
{
/*
* STEP 2.2: Crete the socket file descriptor for our IP address
*/
socketFileDesc = socket(addrIt->ai_family, addrIt->ai_socktype, addrIt->ai_protocol);
if (socketFileDesc == -1) {
fprintf(stderr, "Failed to create socket with error: %d\n", errno);
perror("socket"); // Get error desc
continue; // Try next address
}
/*
* STEP 2.3: Set socket behaviour by making ip address to be re-used if used already
*/
int yes=1;
if (setsockopt(socketFileDesc, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("setsockopt");
exit(1);
}
char ipAdd[INET6_ADDRSTRLEN];
getSocketAddressString(addrIt->ai_addr, ipAdd);
((struct sockaddr_in *)addrIt->ai_addr)->sin_port = atoi("3490");
printf("IP is %s::%d\n", ipAdd,((struct sockaddr_in *)addrIt->ai_addr)->sin_port);
// Connect to the socket
int status;
status = connect(socketFileDesc, addrIt->ai_addr, addrIt->ai_addrlen);
if (status != kSuccess) {
perror("connect");
close(socketFileDesc);
socketFileDesc = -1;
continue;
}
}
return socketFileDesc;
}
int main(int argc, char* argv[])
{
// Check we have data from arguments
if (argc < 3 || argc > 3) {
perror("Invalid command");
printf("Usage: %s hostname portnumber\n", argv[0]);
printf(" %s 192.168.1.2 3490\n", argv[0]);
}
// Setup server address info
struct addrinfo *serverInfo;
struct addrinfo hints;
int status = -1;
memset(&hints, 0, sizeof hints); // Make sure it is empty
hints.ai_family = AF_INET; // IPv4
hints.ai_socktype = SOCK_STREAM; // Use socket stream
((struct sockaddr_in *)&hints.ai_addr)->sin_port = atoi(argv[2]);
status = getaddrinfo(argv[1], "3490", &hints, &serverInfo);
if (status != kSuccess) {
fprintf(stderr, "Failed to get address info %s\n", gai_strerror(status));
exit(1);
}
printf("Connecting to %s::%s...\n", argv[1], argv[2]);
// Create and bind socket
int sockfd = createAndConnectSocket(serverInfo);
freeaddrinfo(serverInfo); // We are done with serverinfo
if (sockfd == -1) {
exit(1);
}
// Send and receive data from server
long bytesReceived = -1;
long bytesSent = 0;
const size_t kMaxBufferSize = 50;
char buff[kMaxBufferSize];
const char *msg = "Hi! I am client!";
size_t msgLen = strlen(msg);
printf("Connected to server\n");
// Loop to send and receive data
while (1) {
while (bytesSent < msgLen) {
bytesSent = send(sockfd, msg, msgLen, 0);
printf("Bytes sent %ld\n", bytesSent);
}
bytesReceived = recv(sockfd, &buff, kMaxBufferSize - 1, 0);
if (bytesReceived > 0)
{
printf("Data received from server: %s\n", buff);
}
else if (bytesReceived < 0) {
perror("Read error");
break;
}
else if (bytesReceived == 0) {
printf("Connection closed by server\n");
break;
}
}
// Close socket
close(sockfd);
return 0;
}
My problem is: Even though I have set the port and IP in getaddrinfo() call, but when it is binding or connecting the port number found in sockaddr struct is wrong as it is different value. I do know what is happing here, and I get connection refused message when I do that because of that.
Can anyone please take a look at my program and tell me why I am getting connection refused ? I would really appreciate if someone can suggest any improvements in my code.
Thanks
You're not connecting to the port you think you're connecting to.
((struct sockaddr_in *)addrIt->ai_addr)->sin_port = atoi("3490");
The value of sin_port must be in network byte order, i.e. big endian. You're instead assigning the value 3490 (via atoi) directly, so the value is in host byte order. Your platform is most likely using little endian byte ordering.
As a result instead of connecting to port 3490 (0DA2 hex) you're connecting to port 41485 (A2 0D hex).
You need to use the htons function, which converts a 16 bit value (since sin_port is a 16 bit field) from host byte order to network byte order. Also, there's no need to use atoi here. Just use a numeric constant instead.
((struct sockaddr_in *)addrIt->ai_addr)->sin_port = htons(3490);
End goal:
For the parent process of the server to know what clients join or leave the multicast group. So far I've only tried to check on clients joining, for I assume checking on those leaving is a similar matter.
My method(s) so far:
Checking for changes in the socket of the multicast group through select().
After joining, the client executes a sendto() directed to the (parent process of) the server program. The select() in the server is meant to recognize any changes, but apparently doesn't, and thus retval != 0 is never true.
Results so far
I Have tried with many different IP addresses and constants such as INADDR_ANY, but I've only managed as far as sending a message back to the client through the multicast, and this one interpret it as if the server-program had sent it. The most common result is the server-program not receiving any message at all.
Here is my client code:
/* Receiver/client multicast Datagram*/
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_MSG 100
struct sockaddr_in localSock, servSock;
struct ip_mreq group;
int sd, n;
int datalen, mcastport;
char msg[MAX_MSG];
int main(int argc, char *argv[])
{
if(argc!=3) {
printf("usage : %s <address> <port>\n",argv[0]);
exit(0);
}
mcastport = atoi(argv[2]);
/* Create a datagram socket on which to receive. */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if(sd < 0)
{
perror("Opening datagram socket error");
exit(1);
}
else
printf("Opening datagram socket....OK.\n");
/* Enable SO_REUSEADDR to allow multiple instances of this */
/* application to receive copies of the multicast datagrams. */
{
int reuse = 1;
if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
{
perror("Setting SO_REUSEADDR error");
close(sd);
exit(1);
}
else
printf("Setting SO_REUSEADDR...OK.\n");
}
/* Bind to the proper port number with the IP address */
/* specified as INADDR_ANY. */
memset((char *) &localSock, 0, sizeof(localSock));
localSock.sin_family = AF_INET;
localSock.sin_port = htons(mcastport);
localSock.sin_addr.s_addr = INADDR_ANY;
if(bind(sd, (struct sockaddr*)&localSock, sizeof(localSock)))
{
perror("Binding datagram socket error");
close(sd);
exit(1);
}
else
printf("Binding datagram socket...OK.\n");
printf("Enter the group's name you want to join:\n");
scanf("%s", msg);
/* Join the multicast group 226.1.1.1 on the local IP address */
/* interface. Note that this IP_ADD_MEMBERSHIP option must be */
/* called for each local interface over which the multicast */
/* datagrams are to be received. */
group.imr_multiaddr.s_addr = inet_addr(argv[1]);
group.imr_interface.s_addr = inet_addr("127.0.0.1");
if(setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0)
{
perror("Adding multicast group error");
close(sd);
exit(1);
}
else
printf("Adding multicast group...OK.\n");
/* Initialize the group sockaddr structure with a */
/* group address of 226.1.1.1 and port given by user. */
memset((char *) &servSock, 0, sizeof(servSock));
servSock.sin_family = AF_INET;
servSock.sin_addr.s_addr = inet_addr(argv[1]);
servSock.sin_port = htons(mcastport);
if(sendto(sd, "", 1, 0, (struct sockaddr*) &servSock, sizeof(servSock)) < 0)
{perror("Sending datagram message error");}
else
printf("Sending datagram message...OK\n");
/* Read from the socket. */
if((n=read(sd, msg, MAX_MSG)) < 0)
{
perror("Reading datagram message error");
close(sd);
exit(1);
}
else
{
printf("Reading datagram message...OK.\n");
printf("The message from multicast server is: \"%s\"\n", msg);
}
msg[n] = '\0';
return 0;
}
This is my server program code:
/* Send Multicast Datagram code*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h> /* for strncpy, memset */
#define MAX_MSG 100
struct in_addr localInterface;
struct sockaddr_in groupSock, cliAddr;
int sd, mcastport, maxJoin, maxJoined = 0, pipefd[2], cliLen, cpid;
char msg[MAX_MSG], groupName[MAX_MSG];
int main (int argc, char *argv[ ])
{
/* check command line args */
if(argc < 2) {
printf("usage : %s <port> \n", argv[0]);
exit(1);
}
mcastport = atoi(argv[1]);
/* Create a datagram socket on which to send. */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if(sd < 0)
{
perror("Opening datagram socket error");
exit(1);
}
else
printf("Opening the datagram socket...OK\n");
/* Initialize the group sockaddr structure with a */
/* group address of 225.1.1.1 and port given by user. */
memset((char *) &groupSock, 0, sizeof(groupSock));
groupSock.sin_family = AF_INET;
groupSock.sin_addr.s_addr = inet_addr("226.1.1.1");
groupSock.sin_port = htons(mcastport);
printf("Create a group: ");
scanf("%s", groupName);
printf("Maximum number of clients that can join the group? ");
scanf("%d", &maxJoin);
/* Disable loopback so you do not receive your own datagrams.
{
char loopch = 0;
if(setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopch, sizeof(loopch)) < 0)
{
perror("Setting IP_MULTICAST_LOOP error");
close(sd);
exit(1);
}
else
printf("Disabling the loopback...OK.\n");
}
*/
/* Set local interface for outbound multicast datagrams. */
/* The IP address specified must be associated with a local, */
/* multicast capable interface. */
printf("Setting the local interface...");
localInterface.s_addr = inet_addr("127.0.0.1");
if(setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, (char *)&localInterface, sizeof(localInterface)) < 0)
{
perror("error");
exit(1);
}
else
printf("OK\n");
if((cpid = fork()) == 0) //child process --sends messages
{
/* Send a message to the multicast group specified by the*/
/* groupSock sockaddr structure. */
printf("Enter a message to send: \n");
scanf("%s", msg);
if(sendto(sd, msg, strlen(msg)+1, 0, (struct sockaddr*)&groupSock, sizeof(groupSock)) < 0)
{perror("Sending datagram message error");}
else
printf("Sending datagram message...OK\n");
/* Try the re-read from the socket if the loopback is not disable
if(read(sd, databuf, datalen) < 0)
{
perror("Reading datagram message error\n");
close(sd);
exit(1);
}
else
{
printf("Reading datagram message from client...OK\n");
printf("The message is: %s\n", databuf);
}
*/
exit(EXIT_SUCCESS);
}
else //parent process --checks for JOINs and QUITs
{
fd_set rfds;
struct timeval tv;
int retval, status;
while (waitpid(cpid, &status, WNOHANG) != cpid)
{
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(sd, &rfds);
/* Wait up to five seconds. */
tv.tv_sec = 5;
tv.tv_usec = 0;
retval = select(sd+1, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */
if (retval == -1)
perror("select()");
else if (retval != 0)
{
printf("Data is available now.\n");
/* FD_ISSET(0, &rfds) will be true. */
cliLen = sizeof(cliAddr);
int n;
if((n = recvfrom(sd, msg, MAX_MSG, 0, (struct sockaddr *) &cliAddr,&cliLen)) == -1)
perror("Some bullshit happened");
msg[n] = '\0';
printf("Client IP:port is: %s:%d", inet_ntoa(cliAddr.sin_addr), (int) ntohs(cliAddr.sin_port));
} else
{printf("no data.\n");}
}
exit(0);
}
return 0;
}
Possible solutions I haven't tried:
Maybe I shouldn't use the multicast group to send information client->server, but rather another type of connection? I'm just guessing here. I know you guys don't like doing anyone's work.
I have been at this "simple" issue for several hours and tried reading everywhere I could, including this question which seems very similar, but I haven't managed to solve it in any way. I'm completely striking out here.
If the client sends to the multicast group and the server expects to read that, the server needs to join the multicast group as well.
It isn't a great solution, as all the other client members will also receive that multicast.
It would make more sense for the client to first receive a multicast from the server, and then to respond to the server's address, which is provided via the result arguments of recvfrom().
Two points that may help you:
There is no need to use multicasting if your communication is only local (you use 127.0.0.1 in your code)
Multicast groups are joined by network interfaces, not by processes. Once a network interface has joined a multicast interface, a second joining of the same network interface to the same multicast group will change nothing. Even when it's another process on the same host that requests the second
joining.