Related
I've run into a problem with UDP sockets.
For this particular program, a single .c file needs to be both a client to another server (via TCP) and a server/client to itself (executed twice, running on separate servers). It will be running twice at the same time and since it needs to be able to do both the TCP connection (for one type of data) and the UDP connection (for a different type of data) at the same time it needed to be done with threads or forks, but I used threads.
The issue I'm having is the UDP sockets aren't receiving any datagrams from each other. There are no compilation errors and it runs fine, but there's no output other than general debugging print statements. It's getting stuck at the recvfrom commands.
The code below is separated into two parts (again, within the same .c file). The top portion is the server section, and the lower portion is the client section. This is all done WITHIN a thread. I tried creating the socket THEN calling the thread with the client code (the idea was the thread would communicate with the parent but it didn't matter), but it gets the same result. So, for now, the thread just handles the UDP connection and the parent deals with the TCP.
If you need any more explanation, please feel free to ask. This is for a school assignment so I can't give TOO much, but I'll say what I can.
Thank you!
QUICK EDIT: All this code below is doing is just sending hello to the server and back to the client. Further details are not needed.
Assume that argv->stuff is the struct that I passed to the thread and that the user provides the server, IP address, and port when executing.
//----- Server portion of code is below
int cli2_sockfd;
char buffer_cli2[MAXLINE];
char *hello2 = "Hello from client 2";
struct sockaddr_in cli2_addr, client1_addr;
int clis_portno = atoi(argv->port);
clis_portno = clis_portno + 1;
// Creating socket file descriptor
if ( (cli2_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&cli2_addr, 0, sizeof(cli2_addr));
memset(&client1_addr, 0, sizeof(client1_addr));
// Filling server information
cli2_addr.sin_family = AF_INET; // IPv4
cli2_addr.sin_addr.s_addr = INADDR_ANY;
cli2_addr.sin_port = htons(clis_portno);
// Bind the socket with the server address
if ( bind(cli2_sockfd, (const struct sockaddr *)&cli2_addr,
sizeof(cli2_addr)) < 0 )
{
perror("bind failed");
exit(EXIT_FAILURE);
}
while(1)
{
int n2;
socklen_t len2;
if((n2 = recvfrom(cli2_sockfd, (char *)buffer_cli2, MAXLINE,
0, ( struct sockaddr *) &client1_addr,
&len2)) < 0)
{
perror("svr recvfrom");
exit(EXIT_FAILURE);
}
buffer_cli2[n2] = '\0';
printf("Client 1: %s\n", buffer_cli2);
if(sendto(cli2_sockfd, (const char *)hello2, strlen(hello2),
MSG_CONFIRM, (const struct sockaddr *) &client1_addr,
len2) < 0)
{
perror("svr sendto");
exit(EXIT_FAILURE);
}
printf("Hello message sent.\n");
}
//----- The client portion of the code is below
int client1_sockfd;
char buffer[MAXLINE];
char *hello1 = "Hello from client 1";
struct sockaddr_in client2_addr;
struct hostent *client_2;
clis_portno = atoi(argv->port);
clis_portno = clis_portno + 1;
// Creating socket file descriptor
if ( (client1_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&client2_addr, 0, sizeof(client2_addr));
if((client_2 = gethostbyname(argv->name)) == NULL)
{
perror("cli gethostbyname");
exit(EXIT_FAILURE);
}
bzero((char *) &client2_addr, sizeof(client2_addr));
// Filling Client 2 information
client2_addr.sin_family = AF_INET;
bcopy((char *)client_2->h_addr, (char *)&client2_addr.sin_addr.s_addr, client_2->h_length);
client2_addr.sin_port = htons(clis_portno);
while(1)
{
int n1;
socklen_t len1;
if( sendto(client1_sockfd, (const char *)hello1, strlen(hello1),
0, (const struct sockaddr *) &client2_addr,
sizeof(client2_addr)) < 0)
{
perror("cli sendto");
exit(EXIT_FAILURE);
}
printf("IN THREAD: Hello1 = %s\n", hello1);
if((n1 = recvfrom(client1_sockfd, (char *)buffer, MAXLINE,
MSG_WAITALL, (struct sockaddr *) &client2_addr,
&len1)) < 0)
{
perror("cli recvfrom");
exit(EXIT_FAILURE);
}
buffer[n1] = '\0';
printf("IN THREAD: Client 2 : %s\n", buffer);
}
You are forgetting to initialize len2:
socklen_t len2;
if((n2 = recvfrom(cli2_sockfd, (char *)buffer_cli2, MAXLINE,
0, ( struct sockaddr *) &client1_addr,
&len2)) < 0)
Better:
socklen_t len2 = sizeof(client1_addr);
n2 = recvfrom(cli2_sockfd, (char *)buffer_cli2, MAXLINE,
0, ( struct sockaddr *) &client1_addr,
&len2));
if (n2 < 0)
{
….
Not sure if that's your only issue that's preventing packets from being received.
I cleaned up your code a little and got it to work using port 9999 for server. And having the client connect to localhost. I cleaned up some of those memcpy statements around gethostbyname, some of your struct initialization calls, removed some of the exit calls that could occur for benign errors (including recvfrom errors when the server is offline). That MSG_WAITALL flag looked weird, so I removed that as well.
I got it working Cygwin without any special hacks. I have no doubt it would work in Linux (or any Unix).
You can see it working here in server mode:
And the corresponding window in client mode:
Code here:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <stdlib.h>
#include <memory.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <stdarg.h>
#define MAXLINE 260
#define MSG_CONFIRM "Confirm"
void server(unsigned short port)
{
int cli2_sockfd = -1;
char buffer_cli2[MAXLINE] = { 0 };
char *hello2 = "Hello from client 2";
struct sockaddr_in cli2_addr = { 0 }, client1_addr = { 0 };
unsigned short clis_portno = port;
// Creating socket file descriptor
if ((cli2_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// Filling server information
cli2_addr.sin_family = AF_INET; // IPv4
cli2_addr.sin_addr.s_addr = INADDR_ANY;
cli2_addr.sin_port = htons(clis_portno);
// Bind the socket with the server address
if (bind(cli2_sockfd, (const struct sockaddr *)&cli2_addr,
sizeof(cli2_addr)) < 0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
while (1)
{
int n2;
socklen_t len2 = sizeof(client1_addr);
if ((n2 = recvfrom(cli2_sockfd, (char *)buffer_cli2, MAXLINE,
0, (struct sockaddr *) &client1_addr,
&len2)) < 0)
{
perror("svr recvfrom");
exit(EXIT_FAILURE);
}
buffer_cli2[n2] = '\0';
printf("Client 1: %s\n", buffer_cli2);
if (sendto(cli2_sockfd, (const char *)hello2, strlen(hello2),
0, (const struct sockaddr *) &client1_addr,
len2) < 0)
{
perror("svr sendto");
}
printf("Hello message sent.\n");
}
}
void client(const char* hostname, unsigned short port)
{
int client1_sockfd;
char buffer[MAXLINE];
char *hello1 = "Hello from client 1";
struct sockaddr_in client2_addr = { 0 };
struct hostent *client_2 = NULL;
unsigned short clis_portno = port;
// Creating socket file descriptor
if ((client1_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
if ((client_2 = gethostbyname(hostname)) == NULL)
{
perror("cli gethostbyname");
exit(EXIT_FAILURE);
}
// Filling Client 2 information
client2_addr.sin_family = AF_INET;
client2_addr.sin_port = htons(clis_portno);
memcpy(&client2_addr.sin_addr, client_2->h_addr, 4);
while (1)
{
int n1;
if (sendto(client1_sockfd, (const char *)hello1, strlen(hello1),
0, (const struct sockaddr *) &client2_addr,
sizeof(client2_addr)) < 0)
{
perror("cli sendto");
exit(EXIT_FAILURE);
}
printf("IN THREAD: Hello1 = %s\n", hello1);
socklen_t len1 = sizeof(client2_addr);
if ((n1 = recvfrom(client1_sockfd, (char *)buffer, MAXLINE,
0, (struct sockaddr *) &client2_addr,
&len1)) < 0)
{
perror("cli recvfrom");
}
else
{
buffer[n1] = '\0';
printf("IN THREAD: Client 2 : %s\n", buffer);
}
sleep(1);
}
}
int main(int argc, char** argv)
{
if ((argc > 1) && (strcmp(argv[1], "s") == 0))
{
printf("Running in server mode\n");
server(9999);
}
else
{
printf("Running in client mode\n");
client("localhost", 9999);
}
return 0;
}
I am beginner in socket programming and reading Linux Network Programming book. I decided to implement client-server connection as shown in the book. Server program is run on Ubuntu 14.04 machine and client code is run from Mac machine. The server code is the following
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
const char message[] = "hello, world\n";
int main()
{
int sock = 0;
int port = 0;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1)
fprintf(stderr, "failed\n");
else
printf("connection is establisshed\n");
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY );
server.sin_port = 3500;
int status = bind(sock, (struct sockaddr*) &server, sizeof(server));
if (status == 0)
printf("connection completed\n");
else
printf("problem is encountered\n");
status = listen(sock, 5);
if (status == 0)
printf("app is ready to work\n");
else
{
printf("connection is failed\n");
return 0;
}
while (1)
{
struct sockaddr_in client = { 0 };
int sclient = 0;
int len = sizeof(client);
int childSocket = accept(sock, (struct sockaddr*) &client, &len);
if (childSocket == -1)
{
printf("cannot accept connection\n");
close(sock);
break;
}
write(childSocket, message, strlen(message));
close(childSocket);
}
return 0;
}
As for client side i wrote the following code
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
int main(int argc, char* argv[])
{
int sock = 0;
int port = 0;
struct sockaddr_in servaddr;
sock = socket(AF_INET, SOCK_STREAM, 0);
int status = 0;
char buffer[256] = "";
if (sock == -1)
{
printf("could not establish connection\n");
exit(1);
}
port = 3500;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
servaddr.sin_port = htons(port);
status = connect(sock, (struct sockaddr*) &servaddr, sizeof(servaddr));
if (status == 0)
printf("connection is established successfully\n");
else
{
printf("could not run the app\n");
exit(1);
}
status = read(sock, buffer, sizeof(buffer));
if (status > 0)
printf("%d: %s", status, buffer);
close(sock);
return 0;
}
To get IP address of client machine I run ifconfig from terminal an get inet_addr 192.168.1.165 value. Now when I pass that address string as command line argument I get message that app is not running message. There is problem with address that I got, as I understand. So what is the problem?
Thanks in advance
Most probably the server does not listen on the port you are assuming, that is 3500.
To fix this, change this line:
server.sin_port=3500
to be
server.sin_port = htons(3500);
(To monitor which process is listing on which address:port you might like to use the netstat command line tool. In your case probably using the options -a -p -n )
Also on recent systems accept() expects a pointer to socklen_t as last parameter, so change this
int len=sizeof(client);
to be
socklen_t len = sizeof client; /* sizeof is an operator, not a function¨*/
I am writing a TCP client in C.
Following several tutorial I wrote my code but it can accept only the first connection to the server.
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h> //inet_addr for INADDR_ANY
#include <string.h> //for splitting (strtok)
#include <pthread.h> //thread library
#include <time.h>
#include <unistd.h> //for function close()
void* SocketHandler(void*);
int main(void) {
//socket parameters
int server_socket_desc;
int clientAddressLength = sizeof(struct sockaddr_in);
struct sockaddr_in server_addr, client_addr;
const unsigned short int PORT_NUMBER = 8963;
server_socket_desc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server_socket_desc < -1) {
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server_addr.sin_family = AF_INET; //it should be always set to AF_INET
//set the server address
server_addr.sin_addr.s_addr = inet_addr("192.168.123.240");
//server_addr.sin_addr.s_addr = inet_addr("31.185.101.35");
//server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(PORT_NUMBER);
//Bind
if (bind(server_socket_desc, (struct sockaddr *) &server_addr,
sizeof(server_addr)) < 0) {
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(server_socket_desc, 10);
//Accept and incoming connection
puts("Waiting for incoming connections...");
//accept connection from an incoming client
while (1) {
int *temp_socket_desc = (int*) malloc(sizeof(int));
if ((*temp_socket_desc = accept(server_socket_desc,
(struct sockaddr *) &client_addr,
(socklen_t*) &clientAddressLength)) != -1) {
printf("----------\nConnection accepted \n");
sleep(1);
pthread_t thread_id;
int *client_socket_desc = (int*) malloc(sizeof(int));
client_socket_desc = temp_socket_desc;
pthread_create(&thread_id, NULL, &SocketHandler,
(void*) client_socket_desc);
//if thread has not terminated, pthread_detach() shall not cause it to terminate
pthread_detach(thread_id);
puts("handler assigned");
} else
puts("connection refused");
}
close(server_socket_desc);
//mysql_close(mysql_conn);
return 0;
}
/*
* This will handle connection for each client
* */
void* SocketHandler(void* lp) {
int *csock = (int*) lp;
char buffer[128];
int buffer_len = 128;
int bytecount;
memset(buffer, 0, buffer_len);
if ((bytecount = read(*csock, buffer, buffer_len) == -1)) {
fprintf(stderr, "Error receiving data\n");
close(*csock);
return 0;
}
printf("Received bytes %d\nReceived string \"%s\"\n", bytecount, buffer);
close(*csock);
free(csock);
puts("exiting thread");
//pthread_exit(0);
return 0;
}
I temporally solved the problem inserting a sleep() after the while loop but it is a very bad solution.
Can somebody explain me why the code does'n work without the sleep?
There is a problem in handling of client_socket_desc:
You allocate it only once. All threads will get the same pointer.
So later accepts will override socket descriptors value of earlier threads.
Try the following change, for allocating own memory block for each thread:
int fd = accept( server_socket_desc, (struct sockaddr *) &client_addr, (socklen_t*)
&clientAddressLength)
if ( fd != -1 )
{
pthread_t thread_id;
int *client_socket_desc = malloc(sizeof(int));
*client_socket_desc = fd;
pthread_create(&thread_id, NULL, &SocketHandler,(void*) client_socket_desc);
...
Or course you must add error handlings for malloc and pthread_create.
And also free the allocated memory when not needed anymore.
I don't understood why there is the following code in the while loop:
if(send(*client_socket_desc,buffer,1,MSG_NOSIGNAL)>0)
{
puts("closing client socket");
close(*client_socket_desc);
}
Close client sockets in client handler threads.
I am trying to implement a tcp client and tcp server. I am able to establish the connection but when I send a message from the client, the server doesn't receive it and yes I did look at the previous posts and there were alot of similar problems. I did follow them but I am still getting the same error. The error i am getting is from server side:
recv: Socket operation on non-socket
Here is my code. If you can please let me know what I am doing wrong, I would really appreciate it. I think there is a problem in my server implementation.
Server:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 3490
#define BACKLOG 10
int main()
{
struct sockaddr_in server;
struct sockaddr_in dest;
int status,socket_fd, client_fd,num;
socklen_t size;
char buffer[10240];
memset(buffer,0,sizeof(buffer));
int yes = 1;
if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0))== -1) {
fprintf(stderr, "Socket failure!!\n");
exit(1);
}
if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
memset(&server, 0, sizeof(server));
memset(&dest,0,sizeof(dest));
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = INADDR_ANY;
if ((bind(socket_fd, (struct sockaddr *)&server, sizeof(struct sockaddr )))== -1) { //sizeof(struct sockaddr)
fprintf(stderr, "Binding Failure\n");
exit(1);
}
if ((listen(socket_fd, BACKLOG))== -1){
fprintf(stderr, "Listening Failure\n");
exit(1);
}
while(1) {
size = sizeof(struct sockaddr_in);
if ((client_fd = accept(socket_fd, (struct sockaddr *)&dest, &size)==-1)) {
//fprintf(stderr,"Accept Failure\n");
perror("accept");
exit(1);
}
printf("Server got connection from client %s\n", inet_ntoa(dest.sin_addr));
//buffer = "Hello World!! I am networking!!\n";
if ((num = recv(client_fd, buffer, 10239,0))== -1) {
//fprintf(stderr,"Error in receiving message!!\n");
perror("recv");
exit(1);
}
// num = recv(client_fd, buffer, sizeof(buffer),0);
buffer[num] = '\0';
printf("Message received: %s\n", buffer);
close(client_fd);
return 0;
//close(socket_fd);
}
}
Client:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 3490
int main(int argc, char *argv[])
{
struct sockaddr_in server_info;
struct hostent *he;
int socket_fd,num;
char *buffer;
if (argc != 2) {
fprintf(stderr, "Usage: client hostname\n");
exit(1);
}
if ((he = gethostbyname(argv[1]))==NULL) {
fprintf(stderr, "Cannot get host name\n");
exit(1);
}
if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0))== -1) {
fprintf(stderr, "Socket Failure!!\n");
exit(1);
}
memset(&server_info, 0, sizeof(server_info));
server_info.sin_family = AF_INET;
server_info.sin_port = htons(PORT);
server_info.sin_addr = *((struct in_addr *)he->h_addr);
if (connect(socket_fd, (struct sockaddr *)&server_info, sizeof(struct sockaddr))<0) {
//fprintf(stderr, "Connection Failure\n");
perror("connect");
exit(1);
}
buffer = "Hello World!! I am networking!!\n";
if ((send(socket_fd,buffer, sizeof(buffer),0))== -1) {
fprintf(stderr, "Failure Sending Message\n");
close(socket_fd);
exit(1);
}
else {
printf("Message being sent: %s\n",buffer);
}
close(socket_fd);
}
I ran the server under gdb, and discovered that client_fd is 0 after the call to accept(). This is an invalid socket fd, so I looked at that line of code and noticed that the closing parenthesis is wrong:
if ((client_fd = accept(socket_fd, (struct sockaddr *)&dest, &size)==-1)) {
should be:
if ((client_fd = accept(socket_fd, (struct sockaddr *)&dest, &size))==-1) {
Otherwise, it's doing the comparison first and then assigning the comparison to client_fd, whereas you want the assignment of the socket, followed by the comparison.
To avoid this exact kind of frustrating bug, it's generally considered best practice to not put assignments inside of 'if' statements. I would recommend instead:
client_fd = accept(...);
if (client_fd < 0) { ... }
Also, in the client, the call to send() uses "sizeof(buffer)". 'buffer' is a char*, and the sizeof a pointer is 4 (on a 32-bit system), so only 'Hell' will be sent. To send the full string, use "strlen(buffer)" instead for the amount to send.
Your first problem is misplaced parentheses.
if ((client_fd = accept(socket_fd, (struct sockaddr *)&dest, &size)==-1)) {
should actually be
if ((client_fd = accept(socket_fd, (struct sockaddr *)&dest, &size))==-1) {
As you currently have it, client_fd will be assigned to the result of the equality test between the return value of accept() and -1 and thus will always be zero in case of success.
This is one reason why many programmers avoid assignments in if statements. If written like this
client_fd = accept(socket_fd, (struct sockaddr *)&dest, &size);
if (client_fd == -1) {
then the error can't occur.
I've been developing this simple client - server application with C where the client is just sending random data to the server and the server just listens to what the client sends. The protocol I'm using is SCTP and I'm interested on how to implement the multihoming feature to it.
I've been searching through the internet about SCTP and multihoming and haven't been able to find any examples about how to instruct SCTP to use multiple addresses for communication. I've only managed to find what commands one should use when trying to setup SCTP with multihoming and it should be quite straightforward.
I've created a client and a server which both use my computers two WLAN interfaces as their connection points. Both adapters are connected to the same AP. The server is listening for data from the client from these interfaces and the client sends data through them. The problem is that when I disconnect the primary WLAN adapter the client is sending data to, the transmission just halts when it should fallback to the secondary connection. I've traced the packets with Wireshark and the first INIT and INIT_ACK packets report that both the client and the server are using the WLAN adapters as their communication links.
When I reconnect the primary WLAN connection the transmission continues after a little while and bursts a huge load of packets to the server which isn't right. The packets should have been transmitted over the secondary connection. On many sites it is said that SCTP switches between connections automagically but in my case that's not happening. So do you guys have any clues why the transmission doesn't fallback to the secondary connection when the primary link is down even though the client and the server knows each others addresses including the secondary address?
About the server:
The server creates a SOCK_SEQPACKET type socket and binds all interfaces found with INADDR_ANY. getladdrs reports that the server is bounded to 3 addresses (including 127.0.0.1). After that the server listens to the socket and waits the client to send data. Server reads the data with sctp_recvmsg call.
About the client:
The client creates also a SEQPACKET socket and connects to an IP-address specified by a commandline argument. getladdrs in this case returns also 3 addresses like in the servers case. After that the client just starts to send data to the server with one second delay to the server until the user interrupts the send with Ctrl-C.
Here's some source code:
Server:
#define BUFFER_SIZE (1 << 16)
#define PORT 10000
int sock, ret, flags;
int i;
int addr_count = 0;
char buffer[BUFFER_SIZE];
socklen_t from_len;
struct sockaddr_in addr;
struct sockaddr_in *laddr[10];
struct sockaddr_in *paddrs[10];
struct sctp_sndrcvinfo sinfo;
struct sctp_event_subscribe event;
struct sctp_prim prim_addr;
struct sctp_paddrparams heartbeat;
struct sigaction sig_handler;
void handle_signal(int signum);
int main(void)
{
if((sock = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)) < 0)
perror("socket");
memset(&addr, 0, sizeof(struct sockaddr_in));
memset((void*)&event, 1, sizeof(struct sctp_event_subscribe));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(PORT);
from_len = (socklen_t)sizeof(struct sockaddr_in);
sig_handler.sa_handler = handle_signal;
sig_handler.sa_flags = 0;
if(sigaction(SIGINT, &sig_handler, NULL) == -1)
perror("sigaction");
if(setsockopt(sock, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe)) < 0)
perror("setsockopt");
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int))< 0)
perror("setsockopt");
if(bind(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr)) < 0)
perror("bind");
if(listen(sock, 2) < 0)
perror("listen");
addr_count = sctp_getladdrs(sock, 0, (struct sockaddr**)laddr);
printf("Addresses binded: %d\n", addr_count);
for(i = 0; i < addr_count; i++)
printf("Address %d: %s:%d\n", i +1, inet_ntoa((*laddr)[i].sin_addr), (*laddr)[i].sin_port);
sctp_freeladdrs((struct sockaddr*)*laddr);
while(1)
{
flags = 0;
ret = sctp_recvmsg(sock, buffer, BUFFER_SIZE, (struct sockaddr*)&addr, &from_len, NULL, &flags);
if(flags & MSG_NOTIFICATION)
printf("Notification received from %s:%u\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
printf("%d bytes received from %s:%u\n", ret, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
}
if(close(sock) < 0)
perror("close");
}
void handle_signal(int signum)
{
switch(signum)
{
case SIGINT:
if(close(sock) != 0)
perror("close");
exit(0);
break;
default: exit(0);
break;
}
}
And the Client:
#define PORT 10000
#define MSG_SIZE 1000
#define NUMBER_OF_MESSAGES 1000
#define PPID 1234
int sock;
struct sockaddr_in *paddrs[10];
struct sockaddr_in *laddrs[10];
void handle_signal(int signum);
int main(int argc, char **argv)
{
int i;
int counter = 1;
int ret;
int addr_count;
char address[16];
char buffer[MSG_SIZE];
sctp_assoc_t id;
struct sockaddr_in addr;
struct sctp_status status;
struct sctp_initmsg initmsg;
struct sctp_event_subscribe events;
struct sigaction sig_handler;
memset((void*)&buffer, 'j', MSG_SIZE);
memset((void*)&initmsg, 0, sizeof(initmsg));
memset((void*)&addr, 0, sizeof(struct sockaddr_in));
memset((void*)&events, 1, sizeof(struct sctp_event_subscribe));
if(argc != 2 || (inet_addr(argv[1]) == -1))
{
puts("Usage: client [IP ADDRESS in form xxx.xxx.xxx.xxx] ");
return 0;
}
strncpy(address, argv[1], 15);
address[15] = 0;
addr.sin_family = AF_INET;
inet_aton(address, &(addr.sin_addr));
addr.sin_port = htons(PORT);
initmsg.sinit_num_ostreams = 2;
initmsg.sinit_max_instreams = 2;
initmsg.sinit_max_attempts = 5;
sig_handler.sa_handler = handle_signal;
sig_handler.sa_flags = 0;
if(sigaction(SIGINT, &sig_handler, NULL) == -1)
perror("sigaction");
if((sock = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)) < 0)
perror("socket");
if((setsockopt(sock, SOL_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg))) != 0)
perror("setsockopt");
if((setsockopt(sock, SOL_SCTP, SCTP_EVENTS, (const void *)&events, sizeof(events))) != 0)
perror("setsockopt");
if(sendto(sock, buffer, MSG_SIZE, 0, (struct sockaddr*)&addr, sizeof(struct sockaddr)) == -1)
perror("sendto");
addr_count = sctp_getpaddrs(sock, 0, (struct sockaddr**)paddrs);
printf("\nPeer addresses: %d\n", addr_count);
for(i = 0; i < addr_count; i++)
printf("Address %d: %s:%d\n", i +1, inet_ntoa((*paddrs)[i].sin_addr), (*paddrs)[i].sin_port);
sctp_freepaddrs((struct sockaddr*)*paddrs);
addr_count = sctp_getladdrs(sock, 0, (struct sockaddr**)laddrs);
printf("\nLocal addresses: %d\n", addr_count);
for(i = 0; i < addr_count; i++)
printf("Address %d: %s:%d\n", i +1, inet_ntoa((*laddrs)[i].sin_addr), (*laddrs)[i].sin_port);
sctp_freeladdrs((struct sockaddr*)*laddrs);
i = sizeof(status);
if((ret = getsockopt(sock, SOL_SCTP, SCTP_STATUS, &status, (socklen_t *)&i)) != 0)
perror("getsockopt");
printf("\nSCTP Status:\n--------\n");
printf("assoc id = %d\n", status.sstat_assoc_id);
printf("state = %d\n", status.sstat_state);
printf("instrms = %d\n", status.sstat_instrms);
printf("outstrms = %d\n--------\n\n", status.sstat_outstrms);
for(i = 0; i < NUMBER_OF_MESSAGES; i++)
{
counter++;
printf("Sending data chunk #%d...", counter);
if((ret = sendto(sock, buffer, MSG_SIZE, 0, (struct sockaddr*)&addr, sizeof(struct sockaddr))) == -1)
perror("sendto");
printf("Sent %d bytes to peer\n",ret);
sleep(1);
}
if(close(sock) != 0)
perror("close");
}
void handle_signal(int signum)
{
switch(signum)
{
case SIGINT:
if(close(sock) != 0)
perror("close");
exit(0);
break;
default: exit(0);
break;
}
}
So do you guys have any clues what I'm doing wrong?
Ok I resolved the multihoming problem finally. Here's what I did.
I adjusted the heartbeat value to 5000 ms with sctp_paddrparams struct. The flags variable located in the struct has to in SPP_HB_ENABLE mode because otherwise SCTP ignores the heartbeat value when trying to set the value with setsockopt().
That was the reason why SCTP didn't send heartbeats as often as I wanted. The reason, why I didn't notice the flag variable, was the obsolete reference guide to SCTP I was reading, which stated that there didn't exist a flags variable inside the struct! Newer reference revealed that there was. So heartbeat problem solved!
Another thing was to modify the rto_max value to, for example, 2000 ms or so. Lowering the value tells SCTP to change the path much sooner. The default value was 60 000 ms which was too high (1 minute before it starts to change the path). rto_max value can be adjusted with sctp_rtoinfo struct.
With these two modifications the multihoming started to work. Oh and a another thing. Client has to be in STREAM mode when the Server is in SEQPACKET mode. Client sends data to server with normal send() command and Server read data with sctp_recvmsg() where addr struct is set to NULL.
I hope that this information helps other guys struggling with the multihoming of SCTP. Cheers guys for your opinions, those were a big help for me! Here is some code example so this maybe the first multihoming simple example in the net if you ask me (didnt find any examples than multistreaming examples)
Server:
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <stdlib.h>
#include <pthread.h>
#define BUFFER_SIZE (1 << 16)
#define PORT 10000
int sock, ret, flags;
int i, reuse = 1;
int addr_count = 0;
char buffer[BUFFER_SIZE];
socklen_t from_len;
struct sockaddr_in addr;
struct sockaddr_in *laddr[10];
struct sockaddr_in *paddrs[10];
struct sctp_sndrcvinfo sinfo;
struct sctp_event_subscribe event;
struct sctp_prim prim_addr;
struct sctp_paddrparams heartbeat;
struct sigaction sig_handler;
struct sctp_rtoinfo rtoinfo;
void handle_signal(int signum);
int main(void)
{
if((sock = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)) < 0)
perror("socket");
memset(&addr, 0, sizeof(struct sockaddr_in));
memset(&event, 1, sizeof(struct sctp_event_subscribe));
memset(&heartbeat, 0, sizeof(struct sctp_paddrparams));
memset(&rtoinfo, 0, sizeof(struct sctp_rtoinfo));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(PORT);
from_len = (socklen_t)sizeof(struct sockaddr_in);
sig_handler.sa_handler = handle_signal;
sig_handler.sa_flags = 0;
heartbeat.spp_flags = SPP_HB_ENABLE;
heartbeat.spp_hbinterval = 5000;
heartbeat.spp_pathmaxrxt = 1;
rtoinfo.srto_max = 2000;
/*Set Heartbeats*/
if(setsockopt(sock, SOL_SCTP, SCTP_PEER_ADDR_PARAMS , &heartbeat, sizeof(heartbeat)) != 0)
perror("setsockopt");
/*Set rto_max*/
if(setsockopt(sock, SOL_SCTP, SCTP_RTOINFO , &rtoinfo, sizeof(rtoinfo)) != 0)
perror("setsockopt");
/*Set Signal Handler*/
if(sigaction(SIGINT, &sig_handler, NULL) == -1)
perror("sigaction");
/*Set Events */
if(setsockopt(sock, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe)) < 0)
perror("setsockopt");
/*Set the Reuse of Address*/
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int))< 0)
perror("setsockopt");
/*Bind the Addresses*/
if(bind(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr)) < 0)
perror("bind");
if(listen(sock, 2) < 0)
perror("listen");
/*Get Heartbeat Value*/
i = (sizeof heartbeat);
getsockopt(sock, SOL_SCTP, SCTP_PEER_ADDR_PARAMS, &heartbeat, (socklen_t*)&i);
printf("Heartbeat interval %d\n", heartbeat.spp_hbinterval);
/*Print Locally Binded Addresses*/
addr_count = sctp_getladdrs(sock, 0, (struct sockaddr**)laddr);
printf("Addresses binded: %d\n", addr_count);
for(i = 0; i < addr_count; i++)
printf("Address %d: %s:%d\n", i +1, inet_ntoa((*laddr)[i].sin_addr), (*laddr)[i].sin_port);
sctp_freeladdrs((struct sockaddr*)*laddr);
while(1)
{
flags = 0;
ret = sctp_recvmsg(sock, buffer, BUFFER_SIZE, NULL, 0, NULL, &flags);
if(flags & MSG_NOTIFICATION)
printf("Notification received from %s:%u\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
printf("%d bytes received from %s:%u\n", ret, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
}
if(close(sock) < 0)
perror("close");
}
void handle_signal(int signum)
{
switch(signum)
{
case SIGINT:
if(close(sock) != 0)
perror("close");
exit(0);
break;
default: exit(0);
break;
}
}
Client:
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#define PORT 11000
#define MSG_SIZE 1000
#define NUMBER_OF_MESSAGES 1000
int sock;
struct sockaddr_in *paddrs[5];
struct sockaddr_in *laddrs[5];
void handle_signal(int signum);
int main(int argc, char **argv)
{
int i;
int counter = 0;
int asconf = 1;
int ret;
int addr_count;
char address[16];
char buffer[MSG_SIZE];
sctp_assoc_t id;
struct sockaddr_in addr;
struct sctp_status status;
struct sctp_initmsg initmsg;
struct sctp_event_subscribe events;
struct sigaction sig_handler;
struct sctp_paddrparams heartbeat;
struct sctp_rtoinfo rtoinfo;
memset(&buffer, 'j', MSG_SIZE);
memset(&initmsg, 0, sizeof(struct sctp_initmsg));
memset(&addr, 0, sizeof(struct sockaddr_in));
memset(&events, 1, sizeof(struct sctp_event_subscribe));
memset(&status, 0, sizeof(struct sctp_status));
memset(&heartbeat, 0, sizeof(struct sctp_paddrparams));
memset(&rtoinfo, 0, sizeof(struct sctp_rtoinfo))
if(argc != 2 || (inet_addr(argv[1]) == -1))
{
puts("Usage: client [IP ADDRESS in form xxx.xxx.xxx.xxx] ");
return 0;
}
strncpy(address, argv[1], 15);
address[15] = 0;
addr.sin_family = AF_INET;
inet_aton(address, &(addr.sin_addr));
addr.sin_port = htons(PORT);
initmsg.sinit_num_ostreams = 2;
initmsg.sinit_max_instreams = 2;
initmsg.sinit_max_attempts = 1;
heartbeat.spp_flags = SPP_HB_ENABLE;
heartbeat.spp_hbinterval = 5000;
heartbeat.spp_pathmaxrxt = 1;
rtoinfo.srto_max = 2000;
sig_handler.sa_handler = handle_signal;
sig_handler.sa_flags = 0;
/*Handle SIGINT in handle_signal Function*/
if(sigaction(SIGINT, &sig_handler, NULL) == -1)
perror("sigaction");
/*Create the Socket*/
if((ret = (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP))) < 0)
perror("socket");
/*Configure Heartbeats*/
if((ret = setsockopt(sock, SOL_SCTP, SCTP_PEER_ADDR_PARAMS , &heartbeat, sizeof(heartbeat))) != 0)
perror("setsockopt");
/*Set rto_max*/
if((ret = setsockopt(sock, SOL_SCTP, SCTP_RTOINFO , &rtoinfo, sizeof(rtoinfo))) != 0)
perror("setsockopt");
/*Set SCTP Init Message*/
if((ret = setsockopt(sock, SOL_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg))) != 0)
perror("setsockopt");
/*Enable SCTP Events*/
if((ret = setsockopt(sock, SOL_SCTP, SCTP_EVENTS, (void *)&events, sizeof(events))) != 0)
perror("setsockopt");
/*Get And Print Heartbeat Interval*/
i = (sizeof heartbeat);
getsockopt(sock, SOL_SCTP, SCTP_PEER_ADDR_PARAMS, &heartbeat, (socklen_t*)&i);
printf("Heartbeat interval %d\n", heartbeat.spp_hbinterval);
/*Connect to Host*/
if(((ret = connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr)))) < 0)
{
perror("connect");
close(sock);
exit(0);
}
/*Get Peer Addresses*/
addr_count = sctp_getpaddrs(sock, 0, (struct sockaddr**)paddrs);
printf("\nPeer addresses: %d\n", addr_count);
/*Print Out Addresses*/
for(i = 0; i < addr_count; i++)
printf("Address %d: %s:%d\n", i +1, inet_ntoa((*paddrs)[i].sin_addr), (*paddrs)[i].sin_port);
sctp_freepaddrs((struct sockaddr*)*paddrs);
/*Start to Send Data*/
for(i = 0; i < NUMBER_OF_MESSAGES; i++)
{
counter++;
printf("Sending data chunk #%d...", counter);
if((ret = send(sock, buffer, MSG_SIZE, 0)) == -1)
perror("write");
printf("Sent %d bytes to peer\n",ret);
sleep(1);
}
if(close(sock) != 0)
perror("close");
}
void handle_signal(int signum)
{
switch(signum)
{
case SIGINT:
if(close(sock) != 0)
perror("close");
exit(0);
break;
default: exit(0);
break;
}
}
You client opens an assosiation by using sendto() call. It is OK.
But after that you should not use sendto() anymore. Because sendto() will propably force SCTP to use interface of the given IP.
So, use write() or send() instead of sendto():
counter++;
printf("Sending data chunk #%d...", counter);
if((ret = write(sock, buffer, MSG_SIZE) == -1)
perror("write");
I have never tried SCTP but according to this site it supports two models.
one-to-one style and one-to-many style.
As far as I understand multihoming works for one-to-one style.
In order to open a one-to-one style socket you need a call like :
connSock = socket( AF_INET, SOCK_STREAM, IPPROTO_SCTP );
Note that SOCK_STREAM is different than your SOCK_SEQPACKET
When you do
sock = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)
it seems to open one-to-many style socket which I could not understand if it supports multihoming or not.
So try your code with SOCK_STREAM parameter.
Also here is an example that uses SOCK_STREAM.