I am trying to do Socket programming. I've google and looked at problems like mine. However, I can't see to figure out my error.
Whenever I run my code, I get an error in connect() in main in client.c. The error is invalid argument.
Server.c
/* chatroom server */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <pthread.h>
#include <signal.h>
#define MAX_ROOMS 36
#define MAX_NAME_SIZE 56
#define PORT_NUM 12333
#define MSG_SIZE 8
#define MAX_LOAD 246
#define MAX_CRC 64 //max clients
#define MAX_BUF 256
#define SERVER_IP 32
#define DEBUG 0
struct msg {
int type; //create, join, delete
int length; // length or port num
};
struct chat_room {
int socket_d; //socket descriptor
int port;
pthread_t id; //id of chatroom
char name[MAX_NAME_SIZE];
int clients[MAX_ROOMS]; // used to hold the client's master sockets
};
struct chat_room* findRoom(char* name, struct chat_room* chat){
int iterator;
for(iterator = 0; iterator < MAX_ROOMS; iterator++){
if(strcmp(name, chat[iterator].name) && (chat[iterator].port != 0)) {
return &chat[iterator];
}
}
//if room does not exist
return NULL;
}
struct chat_room* joinServer(int chat_socket, char* name, struct chat_room* chat){
struct chat_room* local_chat = findRoom(name, chat);
int i;
if(local_chat != NULL){ //if the chat exists
for(i= 0; i< MAX_CRC; i++){
if(local_chat->clients[i] == 0)
{
local_chat->clients[i] = chat_socket;
}
return local_chat;
}
}
//if server if full or else error
return NULL;
}
int createResponse(int chat_socket, int new_port_num, int type){
struct msg temp;
char temp_buff[MAX_LOAD];
memset(temp_buff, 0, MAX_LOAD);
temp.type = type;
temp.length = new_port_num;
memcpy(temp_buff, &temp, sizeof(temp));
write(chat_socket, temp_buff, MSG_SIZE);
return 0;
}
int joinResponse(int chat_socket, int new_port_num){
struct msg temp;
char temp_buff[MAX_LOAD];
memset(temp_buff, 0, MAX_LOAD);
temp.type = 11;
temp.length = new_port_num;
memcpy(temp_buff, &temp, sizeof(temp));
write(chat_socket, temp_buff, MSG_SIZE);
return 0;
}
int deleteResponse(int chat_socket, struct chat_room* chat){
struct msg temp;
char temp_buff[MAX_LOAD];
int i;
memset(temp_buff, 0, MAX_LOAD);
temp.type = 12;
memcpy(temp_buff, &temp, sizeof(temp));
for(i=0; i<MAX_CRC; i++){
if((chat->clients[i] != chat_socket) && (chat->clients[i] != 0))
write(chat->clients[i],temp_buff, MSG_SIZE);
}
return 0;
}
struct chat_room* addRoom(int chat_socket, char* name, struct chat_room* chat){
int socket_d;
int i;
struct sockaddr_in sock;
static int port = PORT_NUM;
memset(&sock, 0, sizeof(sock));
int temp = -1;
for(i = 0; i<MAX_ROOMS; i++){
if((strcmp(chat[i].name, name) == 0) && (chat[i].port != 0)){
createResponse(chat_socket, chat[i].port, 15);
return NULL;
}
else if((chat[i].port == 0) && (temp== -1)){
temp = i;
}
}
if(temp == -1){
return NULL;
}
socket_d = socket(AF_INET, SOCK_STREAM, 0);
if(socket_d == -1 && DEBUG){
perror("Error creating chatroom socket");
return NULL;
}
sock.sin_family = AF_INET;
port++;
sock.sin_port = htons(port);
if(bind(socket_d, (struct sockaddr*)&sock, sizeof(struct sockaddr_in)) == -1){
perror("error in binding ");
return NULL;
}
chat[temp].socket_d = socket_d;
chat[temp].port = port;
strcpy(chat[temp].name, name);
return &chat[temp];
}
void* chat_room_main(void* chat_room_cluster){
char buf[MAX_LOAD];
int socket_d, chat_socket;
int temp; //temp_fd
int read_val;
int num_clients = 0;
int i;
int clients[MAX_CRC];
fd_set allfd, modfd;
struct chat_room chat_room_para;
memcpy(&chat_room_para, (struct chat_room*)chat_room_cluster, sizeof(struct chat_room));
free(chat_room_cluster);
memset(clients, 0, sizeof(int)*MAX_CRC);
socket_d = chat_room_para.socket_d;
listen(socket_d, 1);
FD_ZERO(&allfd);
FD_SET(socket_d, &allfd);
printf("New Chatroom Started\n");
while(1){
modfd = allfd;
select(FD_SETSIZE, &modfd, NULL, NULL, NULL);
for(temp = 0; temp < FD_SETSIZE; temp++){
if(FD_ISSET(temp, &modfd)){
memset(buf, 0, sizeof(buf));
if(temp == socket_d) {
chat_socket = accept(socket_d, NULL, NULL);
FD_SET(chat_socket, &allfd);
// find an empty spot to add the chat room
for(i = 0; i<MAX_CRC; i++) {
if(clients[i] == 0){
clients[i] = chat_socket;
break;
}
}
sprintf(buf, "Number of people in chatroom: %d", num_clients);
write(chat_socket, buf, strlen(buf));
num_clients++;
}
else{
if(read_val = read(temp, buf, MAX_LOAD) > 0){
for(i = 0; i< MAX_CRC; i++){
if((clients[i] != temp) && (clients[i] != 0)){
write(clients[i], buf, read_val);
}
}
}
else if(read_val <= 0) {
FD_CLR(temp, &allfd);
for(i = 0; i<MAX_CRC; i++){
if(clients[i] == temp)
clients[i] = 0;
}
num_clients--;
close(chat_socket);
}
}
}
}
}
}
int main(int argc, char* argv[]){
int server_socket, chat_socket; //file descriptors for server and chat
int temp; //tempfd
int i, j;
char server_ip[SERVER_IP];
char buf[MAX_BUF];
char msg_buf[MSG_SIZE];
fd_set allfd, modfd;
struct sockaddr_in sock;
struct hostent* host_name;
struct chat_room chatrooms[MAX_ROOMS];
memset(chatrooms, '\0', sizeof(struct chat_room)* MAX_ROOMS);
memset(&sock, '\0', sizeof(sock));
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if(server_socket == -1){
perror("Error creating socket");
return -1;
}
sock.sin_family = AF_INET;
sock.sin_port = htons(PORT_NUM);
sock.sin_addr.s_addr = INADDR_ANY;
if((bind(server_socket, (struct sockaddr*)&sock, sizeof(struct sockaddr_in))) == -1){
perror("Error in bind()");
return -1;
}
listen(server_socket, 1);
FD_ZERO(&allfd);
FD_SET(server_socket, &allfd);
FD_SET(0, &allfd);
printf("\n*******Chatroom Server*******");
while(1){
modfd = allfd;
select(FD_SETSIZE, &modfd, NULL, NULL, NULL);
for(temp = 0; temp < FD_SETSIZE; temp++) {
if(FD_ISSET(temp, &modfd)) {
switch(temp){
case 0:
break;
default:
if(temp == server_socket){
chat_socket = accept(server_socket, NULL, NULL);
}
else{
char msg_buf[MSG_SIZE];
char buf[MAX_LOAD];
char name[MAX_LOAD];
struct msg temp_message;
struct chat_room* local_chat = NULL;
void* (*init_chatroom)() = &chat_room_main;
void* thread_args;
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
memset(buf, 0, sizeof(buf));
memset(msg_buf, 0, sizeof(msg_buf));
msg_buf[19]= 0;
int read_val = read(temp, msg_buf, MSG_SIZE);
if(read_val > 0){
memcpy(&temp_message, msg_buf, sizeof(temp_message));
read(temp, buf, temp_message.length - sizeof(temp_message));
memcpy(name, buf, temp_message.length - sizeof(temp_message));
if(temp_message.type == 0) {//if create
local_chat = addRoom(temp, name, chatrooms);
if(local_chat != NULL){
thread_args = (void*)malloc(sizeof(struct chat_room));
memcpy((struct chat_room*) thread_args, local_chat, sizeof(struct chat_room));
pthread_create(&tid, &attr, init_chatroom, thread_args);
local_chat->id = tid;
createResponse(temp, local_chat->port, 10);
}
}
else if(temp_message.type == 1){ //join
local_chat = joinServer(temp, name, chatrooms);
if(local_chat != NULL){
joinResponse(temp, local_chat->port);
}
}
else if(temp_message.type == 2){ //delete
local_chat = findRoom(name, chatrooms);
printf("Deleting Room\n");
if(local_chat != NULL) {
local_chat->port = 0;
close(local_chat->socket_d);
deleteResponse(temp, local_chat);
for(j = 0; j<MAX_CRC; j++){
if(local_chat->clients[j]!=0) {
FD_CLR(local_chat->clients[j], &modfd);
local_chat->clients[j] = 0;
}
}
pthread_cancel(local_chat->id);
}
}
}
else if(read_val <= 0){
FD_CLR(temp, &allfd);
close(temp);
}
}
}
}
}
}
return 0;
}
Client.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <pthread.h>
#define PORT_NUM 12333
#define MSG_SIZE 8
#define MAX_LOAD 246
#define MAX_BUF 256
#define SERVER_IP 32
struct msg {
int type;
int length;
};
struct thread_para {
int port;
struct hostent* host_name;
};
int sendCmd(int chat_socket, char* buf, int type){ //function for sending the command
struct msg temp;
char temp_buf[MAX_LOAD];
char name[MAX_LOAD];
int iterator;
if(type == 0){
iterator = 6;
}
else if(type == 1){
iterator = 4;
}
else if(type == 2){
iterator = 6;
}
for(; iterator < strlen(buf); iterator++){
if(buf[iterator] == ' ') {
continue;
}
else{
break;
}
}
strcpy(name, buf+iterator);
memset(temp_buf, 0, MAX_LOAD);
temp.type = type;
temp.length = sizeof(temp)+strlen(name)+1; //for \0
memcpy(temp_buf, &temp, sizeof(temp));
memcpy(temp_buf+sizeof(temp), name, strlen(name)+1);
write(chat_socket, temp_buf, temp.length);
return 0;
}
void* connectChat(int port_num, struct hostent* host_name, int master){
char buf[MAX_BUF];
char temp_buf[MAX_BUF];
int chat_socket;
int i;
int input;
int temp; //temp fd
fd_set allfd, modfd;
struct sockaddr_in sock;
printf("Successfully Joined Room\n");
memset(buf, 0, sizeof(buf));
memset(&sock, 0, sizeof(sock));
sock.sin_family = AF_INET;
sock.sin_port = htons(port_num);
memcpy((char*)&sock.sin_addr.s_addr, host_name->h_addr, host_name->h_length);
chat_socket = socket(AF_INET, SOCK_STREAM, 0);
if(chat_socket == -1){
perror("Error in creation");
return NULL;
}
if(connect(chat_socket, (struct sockaddr*)&sock, sizeof(struct sockaddr)) < 0 ){
perror("Error in connection");
return NULL;
}
FD_ZERO(&allfd);
FD_SET(chat_socket, &allfd);
FD_SET(0, &allfd);
FD_SET(master, &allfd);
while(1) {
modfd = allfd;
select(FD_SETSIZE, &modfd, NULL, NULL, NULL);
for(temp = 0; temp< FD_SETSIZE; temp++){
memset(buf, 0, sizeof(buf));
memset(temp, 0, sizeof(buf));
if(temp == 0) { //reading from standard in
input = read(0, buf, MAX_BUF);
buf[input-1] = '\0'; //add termination to end
write(chat_socket, buf, strlen(buf));
}
else if(temp == chat_socket){
input = read(0, buf, MAX_BUF);
buf[input] = '\0';
memcpy(temp, buf, input);
//display message
printf("%s \n", temp_buf);
}
else if(temp == master){
struct msg temp_message;
input = read(temp, buf, MSG_SIZE);
memcpy(&temp_message, buf, MSG_SIZE);
if(temp_message.type == 12){
printf("Chatroom has been deleted, Shutting down chatroom\n");
return NULL;
}
}
}
}
return 0;
}
int main(int argc, char* argv[]){
char buf[MAX_BUF];
int chat_socket;
int i;
int input;
int temp; //temp fd
int accept_input = 1; // take input for stdin to create a chat thread
fd_set allfd, modfd;
char server_ip[SERVER_IP];
struct hostent* host_name;
struct sockaddr_in sock;
struct msg temp_message;
pthread_attr_t tattr;
pthread_t tid;
if(argc < 2) {
printf("Please try ./crc <server IP> \n");
return -1;
}
pthread_attr_init(&tattr);
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
memset(&sock, '\0', sizeof(sock));
sock.sin_family = AF_INET;
sock.sin_port = htons(PORT_NUM);
strcpy(server_ip ,argv[1]);
if((host_name = (struct hostent*)gethostbyname(server_ip)) == NULL){
perror("failed to get host name");
return -1;
}
memcpy((char*)&sock.sin_addr.s_addr, host_name->h_addr, host_name->h_length);
chat_socket = socket(AF_INET, SOCK_STREAM, 0);
if(chat_socket == -1){
perror("Error creating socket");
return -1;
}
if((connect(chat_socket, (struct sockaddr*)&sock, sizeof(sock))) < 0) {
perror("Error connecting");
return -1;
}
FD_ZERO(&allfd); /* first, clear the allfd set */
FD_SET(chat_socket, &allfd); /* adding client to the set */
FD_SET(0, &allfd);
printf("*****Welcome to the Chatroom*****\n");
while(1){
modfd = allfd;
select(FD_SETSIZE, &modfd, NULL, NULL, NULL);
for(temp = 0; temp < FD_SETSIZE; temp++){
if(FD_ISSET(temp, &modfd)){
if(temp == 0){
input = read(0, buf, MAX_BUF);
buf[input-1] = '\0'; //remove \n inserts termination
if((strncasecmp(buf, "create ", 7) == 0)) {
sendCmd(chat_socket, buf, 0);
}
else if((strncasecmp(buf, "join ", 5) == 0)) {
sendCmd(chat_socket, buf, 1);
}
else if((strncasecmp(buf, "delete ", 7)==0)){
sendCmd(chat_socket, buf, 2);
}
else
{
printf("Enter a valid command: create <Room_name>, join <Room_name>, delete <Room_name>\n");
}
}
else if(temp == chat_socket){
input = read(temp, buf, MSG_SIZE);
memcpy(&temp_message, buf, sizeof(temp_message));
if(temp_message.type == 10) {
printf("Created Chatroom\n");
}
else if(temp_message.type == 11){
connectChat(temp_message.length, host_name, chat_socket);
fflush(stdin);
}
else if(temp_message.type == 15) {
printf("Chatroom exits. Type join <Room_name> to join\n");
}
}
}
}
}
close(chat_socket);
return 0;
}
I gave both sets of code just in case it was need. The program is designed to create multiple chat rooms.
invalid argument is the EINVAL error code, which in the context of connect() means:
An invalid argument was detected (e.g., address_len is not valid for the address family, the specified address family is invalid).
You have multiple calls to connect() in your client code (why?), but you did not indicate which call is the one that is failing. In connectChat() at least, sizeof(struct sockaddr) should be sizeof(struct sockaddr_in) instead, or better sizeof(sock), like you do in main().
Also, if either connect() fails, you are leaking the socket returned by socket(). You need to close() it.
Also, gethostbyname() is deprecated, you should be using getaddrinfo() instead. You are creating IPv4 sockets, which only work with IPv4 addresses. You are not checking if gethostbyname() actually returns an IPv4 address (host_name->h_addr_type == AF_INET) before copying the address bytes into your sock variable. At least with getaddrinfo(), you can restrict the output to IPv4 addresses only. You don't have that option with gethostbyname().
Since you're looking for a way to figure out your error, I'll suggest you to use the following Makefile:
CFLAGS=-Wall -g -O2
CC=gcc
LDFLAGS=-lpthread
all: Server Client
Server: Server.c
Client: Client.c
After running make command you'll see a lot of warnings. Some of them:
Server.c: In function ‘createResponse’:
Server.c:81:5: warning: ignoring return value of ‘write’, declared with attribute warn_unused_result [-Wunused-result]
write(chat_socket, temp_buff, MSG_SIZE);
^
Server.c: In function ‘chat_room_main’:
Server.c:237:25: warning: ‘chat_socket’ may be used uninitialized in this function [-Wmaybe-uninitialized]
close(chat_socket);
^
Server.c: In function ‘main’:
Server.c:319:36: warning: array subscript is above array bounds [-Warray-bounds]
msg_buf[19]= 0;
Client.c: In function ‘connectChat’:
Client.c:113:20: warning: passing argument 1 of ‘memset’ makes pointer from integer without a cast
memset(temp, 0, sizeof(buf));
^
So just try to fix these warnings. I mean all of them.
Related
Is it possible to use select for packet sockets? I mean whether its necessary for the socket to be connection-based in order to use select function on it properly?
I'm seeing that the behavior of a socket which I got it by the following socket function call:
int socket_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
is not as I expect. For example, I see that a ping packet which is 60 bytes long when received and read into a 20 bytes length buffer, it waits about a second between each recv function call. I used recvfrom and it didn't help. For this, I ask whether it's correct to use select for a packet socket?
Update
I'm going to include the code to discuss about it:
int MakeBridge(const char *if1, const char *if2)
{
int sock[2];
sock[0] = OpenSocket(if1);
sock[1] = OpenSocket(if2);
int activity;
char buf[20];
const int numSocks = 2;
int nfds = sock[0];
for (int i = 1; i < numSocks; i++)
if (sock[i] > nfds)
nfds = sock[i];
nfds++;
while (true)
{
FD_ZERO(&readfds);
for (int i = 0; i < numSocks; i++)
FD_SET(sock[i], &readfds);
activity = select(nfds, &readfds, NULL, NULL, NULL);
if (activity == -1) // sockets closed
break;
for (int i = 0; i < numSocks; i++)
if (FD_ISSET(_sock[i], &readfds))
{
int len;
CHECK(ioctl(_sock[i], FIONREAD, &len) != -1, "%s", strerror(errno));
printf("socket %d is set\n", i);
printf("total bytes available to read: %d\n", len);
CHECK(len > 0, "");
do
{
int n = min(len, sizeof(buf));
int nbr = recvfrom(_sock[i], buf, n, 0, NULL, NULL);
printf("n %d nbr %d\n", n, nbr);
CHECK(n == nbr, "");
len -= n;
} while (len);
}
}
return 0;
}
Update 2
Not going to segment messages and using large enough buffer makes the code as follows:
// This is a program which is going to make the bridge between two interfaces. brctl is going to be replaced by this program.
#define Uses_CHECK
#define Uses_close
#define Uses_errno
#define Uses_ETH_P_ALL
#define Uses_FD_SET
#define Uses_htons
#define Uses_ifreq
#define Uses_ioctl
#define Uses_printf
#define Uses_signal
#define Uses_sockaddr_ll
#define Uses_socket
#define Uses_strerror
#include <general.dep>
int _sock[2];
int _CtrlCHandler()
{
printf(" terminating...\n");
CHECK(close(_sock[0]) != -1, "");
CHECK(close(_sock[1]) != -1, "");
printf("all sockets closed successfully.\n");
}
void CtrlCHandler(int dummy)
{
_CtrlCHandler();
}
int OpenSocket(const char *ifname)
{
// getting socket
int socket_fd = socket(PF_PACKET, SOCK_RAW/*|SOCK_NONBLOCK*/, htons(ETH_P_ALL));
CHECK(socket_fd != -1, "%s", strerror(errno));
// init interface options struct with the interface name
struct ifreq if_options;
memset(&if_options, 0, sizeof(struct ifreq));
strncpy(if_options.ifr_name, ifname, sizeof(if_options.ifr_name) - 1);
if_options.ifr_name[sizeof(if_options.ifr_name) - 1] = 0;
// enable promiscuous mode
CHECK(ioctl(socket_fd, SIOCGIFFLAGS, &if_options) != -1, "%s", strerror(errno));
if_options.ifr_flags |= IFF_PROMISC;
CHECK(ioctl(socket_fd, SIOCSIFFLAGS, &if_options) != -1, "%s", strerror(errno));
// get interface index
CHECK(ioctl(socket_fd, SIOCGIFINDEX, &if_options) != -1, "%s", strerror(errno));
// bind socket to the interface
struct sockaddr_ll my_addr;
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sll_family = AF_PACKET;
my_addr.sll_ifindex = if_options.ifr_ifindex;
CHECK(bind(socket_fd, (struct sockaddr *)&my_addr, sizeof(my_addr)) != -1, "%s", strerror(errno));
// socket is ready
return socket_fd;
}
int MakeBridge(const char *if1, const char *if2)
{
_sock[0] = OpenSocket(if1);
CHECK_NO_MSG(_sock[0]);
_sock[1] = OpenSocket(if2);
CHECK_NO_MSG(_sock[1]);
printf("sockets %d and %d opened successfully\n", _sock[0], _sock[1]);
fd_set readfds, orig;
int activity;
char buf[1<<16];
signal(SIGINT, CtrlCHandler);
int packetNumber = 0;
const int numSocks = _countof(_sock);
int nfds = _sock[0];
for (int i = 1; i < numSocks; i++)
if (_sock[i] > nfds)
nfds = _sock[i];
nfds++;
FD_ZERO(&orig);
for (int i = 0; i < numSocks; i++)
FD_SET(_sock[i], &orig);
while (true)
{
readfds = orig;
activity = select(nfds, &readfds, NULL, NULL, NULL);
if (activity == -1) // sockets closed
break;
CHECK(activity > 0, "");
for (int i = 0; i < numSocks; i++)
if (FD_ISSET(_sock[i], &readfds))
{
int len = recvfrom(_sock[i], buf, sizeof(buf), MSG_TRUNC, NULL, NULL);
CHECK(len > 0, "");
CHECK(len <= sizeof(buf), "small size buffer");
printf("%10d %d %d\n", ++packetNumber, i, len);
CHECK(sendto(_sock[!i], buf, len, 0, NULL, 0) == len, "");
}
}
return 0;
}
int Usage(int argc, const char *argv[])
{
printf("Usage: %s <if1> <if2>\n", argv[0]);
printf("Bridges two interfaces with the names specified.\n");
return 0;
}
int main(int argc, const char *argv[])
{
if (argc != 3)
return Usage(argc, argv);
CHECK_NO_MSG(MakeBridge(argv[1], argv[2]));
return 0;
}
As a school project , i was asked to build a simple HTTP server which can handle and process multiple and simultaneous requests , and to proof that this server will deliver my home page to the internet browser. (Using RFC 1945/HTTP 1.0)
I took a part of my project so you know how it goes
- the server listens to a fixed port. When it receives a TCP connection request, it sets up a TCP connection through another port and services the request in a separate thread. To simplify this programming task, we will develop the code in two stages. In the first stage, you will write a multi-threaded server that simply displays the contents of the HTTP request message that it receives. After this program is running properly, you will add the code required to generate an appropriate response.
Any ideas or samples?
This is a sample of http server with thread pool which I wrote a year ago:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <pthread.h>
#include <malloc.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/wait.h>
#include <ctype.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <signal.h>
#define KB 1024
/*function declerations*/
void send_content(int fd, int connfd,int isDir,char* path);
void enqueue(int data);
void* dequeue(void* ptr);
void send_to_client(int connfd, char* line);
/*global vars*/
pthread_mutex_t lock;
pthread_cond_t emp;
int sock =0;
int max_threads =0;
int global_count=0;
int finished =1;
int length=0;
/*Queue*/
struct node{
int info;
struct node *ptr;
}*head,*tail;
struct sigaction ready, last;
int main(int argc, char** argv){
int threads;
int requests;
int port;
int i;
int s;
int len_of_packet=1;
int fd;
int port1;
int file;
char content[16000];
char *fileContent ;
int thrd ;
int rc;
char method[KB];
char path[KB];
int s_len=0;
int r_len=0;
int fileLen;
int parsing;
unsigned int addr_size;
struct sockaddr_in serv_addr, client_addr;
struct stat st;
struct dirent *entry;
DIR *dir;
static fd_set readsocks, socks;
char buf[KB] ;
char Uniform_Resource_Identifier[KB];
int servfd;
int socket_of_accept;
off_t chunk=0;
size_t readData;
int sent;
assert (argc ==3 || argc ==4);
threads = strtol(argv[1], NULL, 10);
if ((errno == ERANGE && (threads == LONG_MAX || threads == LONG_MIN))
|| (errno != 0 && threads == 0)) {
perror("Error: strtol has been failed\n");
exit(0);
}
max_threads = threads;
requests = strtol(argv[2], NULL, 10);
if ((errno == ERANGE && (requests == LONG_MAX || requests == LONG_MIN))
|| (errno != 0 && requests == 0)) {
perror("Error: strtol has been failed\n");
exit(0);
}
port = 80;
if (argc == 4){
port = strtol(argv[3], NULL, 10);
if ((errno == ERANGE && (port == LONG_MAX || port == LONG_MIN))
|| (errno != 0 && port == 0)) {
perror("Error: strtol has been failed\n");
exit(0);
}
}
pthread_t threadsArr[threads];
if(pthread_mutex_init(&lock,NULL)!=0){
printf("Error: failed to init mutex\n");
return 1;
}
pthread_cond_init( &emp, NULL);
head=NULL;
tail=NULL;
/*create threads*/
for (thrd=0; thrd<threads;thrd++){
rc = pthread_create(&threadsArr[thrd], NULL, dequeue, (void*) &thrd);
if (rc){
printf("Error: failed to create thread\n");
return 1;
}
}
/* create socket */
servfd = socket(AF_INET, SOCK_STREAM, 0);
sock = servfd;
if (servfd == -1) {
printf("Error creating socket\n");
exit(1);
}
/* init prepernces */
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(port);
/* bind */
setsockopt(servfd, SOL_SOCKET, SO_REUSEADDR, (const char *) &len_of_packet,sizeof(int));
if (bind(servfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1) {
printf("Error: Bind has been failed\n");
perror ("Bind: ");
exit(1);
}
/*listen */
if (listen(servfd, requests) == -1) {
printf("Error: Listen has been failed\n");
perror ("Listen: ");
exit(1);
}
FD_ZERO(&socks);
FD_SET(servfd, &socks);
int startLen = strlen("HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1>Service Unavailable (HTTP 503)</h1></body></html>\r\n");
int endLen = strlen("</h1></body></html>\r\n");
while(1){
sigfillset(&ready.sa_mask);
ready.sa_handler = SIG_IGN;
ready.sa_flags = 0;
if (sigaction(SIGINT, &ready,&last) || sigaction(SIGINT,&last,NULL)){
finished=0;
for(i=0; i<threads; i++){
rc = pthread_join(threadsArr[i], NULL);
if(rc != 0){
printf("Error: join has been failed\n");
perror("Join: ");
return 1;
}
}
pthread_mutex_destroy(&lock);
close(sock);
}
addr_size = sizeof(client_addr);
socket_of_accept = accept(servfd, (struct sockaddr *) &client_addr, &addr_size);
if (socket_of_accept == -1) {
printf("Error: Accept has been failed\n");
perror ("Accept: ");
exit(1);
}
enqueue(socket_of_accept);
if (length <= requests){
/*recieve message*/
r_len = recv(socket_of_accept, buf, KB,0);
if (r_len == -1){
printf("Error: recieve has been %d\n", socket_of_accept);
close(socket_of_accept);
exit(1);
}
sscanf(buf,"%s %s", method, Uniform_Resource_Identifier);
sscanf(Uniform_Resource_Identifier,"%s", path);
printf("method = %s, path = %s\n", method, path);
/*GET OR POST*/
if(strcmp(method, "GET")!= 0 && strcmp(method, "POST") != 0){
char response[] = "HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1>Service Unavailable (HTTP 503)</h1></body></html>\r\n";
s_len = send(socket_of_accept, response, strlen(response), 0);
if (s_len == -1){
printf("Error: failed to send message %s to client %d\n", response, socket_of_accept);
close(socket_of_accept);
exit(1);
}
}
if (stat(path, &st) == -1){ /*file not found*/
char response[] = "HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1>Not Found (HTTP 404)</h1></body></html>\r\n";
s_len = send(socket_of_accept, response, strlen(response), 0);
if (s_len == -1){
printf("Error: failed to send message %s to client %d\n", response, socket_of_accept);
close(socket_of_accept);
exit(1);
}
close(socket_of_accept);
}else {
if(S_ISDIR(st.st_mode)){/*directory*/
if((dir = opendir (path)) != NULL){
send_content(fd, socket_of_accept,1,path);
close(socket_of_accept);
}else{
printf("Error: failed to open directory: %s\n", path);
}
}else if(S_ISREG(st.st_mode) && st.st_size != 0){/*regular file*/
fd=open(path,O_RDONLY);
send_content(fd, socket_of_accept,0,path);
close(file);
close(socket_of_accept);
}
else{/*empty file*/
char response[] = "HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1> </h1></body></html>\r\n";
s_len = send(socket_of_accept, response, strlen(response), 0);
if (s_len == -1){
printf("Error: failed to send message %s to client %d\n", response, socket_of_accept);
close(socket_of_accept);
exit(1);
}
}
}
}else{/*full queue*/
/*send (HTTP 503)*/
char response[3000] = "HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1>Service Unavailable (HTTP 503)</h1></body></html>\r\n";
s_len = send(socket_of_accept, response, strlen(response), 0);
if (s_len == -1){
printf("Error: unable to send a message %s to: %d\n", response, socket_of_accept);
close(socket_of_accept);
exit(1);
}
close(socket_of_accept);
}
}
return 0;
}
void send_content(int fd, int connfd,int isDir,char* path){
char line[KB];
memset(line, 0, sizeof(line));
send_to_client(connfd, "HTTP/1.0 200 OK\r\n\r\n");
int return_value;
if(!isDir){
while ((return_value=read(fd, line, KB)) > 0) {
send_to_client(connfd, line);
memset(line, 0, sizeof(line));
}
if (return_value < 0){
perror("Error read");
send_to_client(connfd, "Error Resorces\n");
return;
}
}
else {
DIR *d;
struct dirent *dir;
d = opendir(path);
if (d)
{
while ((dir = readdir(d)) != NULL)
{
strcpy(line,dir->d_name);
strcat(line,"\n");
send_to_client(connfd,line);
memset(line, 0, sizeof(line));
}
closedir(d);
}
}
}
/*enqueue*/
void enqueue(int data)
{
int rc;
struct node* temp;
temp = (struct node *)malloc(1*sizeof(struct node));
if(temp == NULL){
printf("Error: couldn't allocate memory\n");
exit(1);
}
temp->ptr = NULL;
temp->info = data;
if (pthread_mutex_lock(&lock) !=0){
printf("Error: failed to lock\n");
exit(1);
}
if (length == 0) /*empty queue*/
{
head = temp;
}else
{
tail->ptr = temp;
}
tail = temp;
length++;
rc = pthread_cond_broadcast(&emp);
assert(rc==0);
if (pthread_mutex_unlock(&lock)!=0){
printf("Error: failed to unlock\n");
pthread_exit(0);
}
return;
}
void send_to_client(int connfd, char* line){
int nsent, totalsent;
int notwritten = strlen(line);
/* keep looping until nothing left to write*/
totalsent = 0;
while (notwritten > 0){
/* notwritten = how much we have left to write
totalsent = how much we've written so far
nsent = how much we've written in last write() call */
nsent = write(connfd, line + totalsent, notwritten);
assert(nsent>=0); // check if error occured (client closed connection?)
totalsent += nsent;
notwritten -= nsent;
}
}
/*dequeue*/
void* dequeue(void* ptr)
{
int rc;
int i=0;
int thread = *((int*)ptr);
struct node* temp;
while(finished){
if (pthread_mutex_lock(&lock) !=0){
printf("Error: lock has been failed\n");
pthread_exit(0);
}
while (length == 0)
{
rc = pthread_cond_wait(&emp, &lock);
assert(rc == 0);
}
int info = head->info;
temp = head;
head = head->ptr;
free(temp);
length--;
rc = pthread_cond_broadcast(&emp);
assert(rc==0);
if (pthread_mutex_unlock(&lock)!=0){
printf("Error: unlock has been failed\n");
pthread_exit(0);
}
}
pthread_exit(0);
}
Why? I didn't do anything on the other peer!
I was using massive threads to get data from the server. When the thread count is small, it's ok. But when the thread count is very large, recv() return -1 and errno indicates "Connection reset by peer".
Here is an example to reproduce the issue:
server.cc
#include <arpa/inet.h>
#include <assert.h>
#include <netinet/in.h>
#include <pthread.h>
#include <unistd.h>
char buffer[4096];
inline int send_all(int socket_fd, const char* data, size_t size, int flags)
{
int result;
const char* pos = data;
while (size > 0)
{
result = send(socket_fd, pos, size, flags);
assert(result > 0);
pos += result;
size -= result;
}
return 0;
}
inline int recv_all(int socket_fd, void* data, size_t size, int flags)
{
int result = recv(socket_fd, data, size, flags | MSG_WAITALL);
assert(((size_t) result) == size);
return 0;
}
void* server_thread(void* arg)
{
int socket_fd = (int) ((long) arg);
// recv some info first
recv_all(socket_fd, buffer, 1, 0);
// simulate some computation
for (int i = 0; i < 0xffff; i ++)
for (int j = 0; j < 0xffff; j ++);
// send data
for (int i = 0; i < 4096; i ++)
send_all(socket_fd, buffer, sizeof(buffer), 0);
// the peer is closed, return 0
recv(socket_fd, buffer, 1, MSG_WAITALL);
close(socket_fd);
pthread_detach(pthread_self());
return NULL;
}
int main(void)
{
int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
assert(listen_socket != -1);
struct sockaddr_in listen_address;
listen_address.sin_family = AF_INET;
listen_address.sin_port = htons(11282);
listen_address.sin_addr.s_addr = INADDR_ANY;
int result = bind(listen_socket,
(struct sockaddr*) &listen_address,
sizeof(listen_address));
assert(result != -1);
result = listen(listen_socket, 5);
assert(result != -1);
while (true)
{
int server_socket = accept(listen_socket, NULL, NULL);
assert(server_socket != -1);
pthread_t tid;
result = pthread_create(&tid,
NULL,
server_thread,
(void *) ((long) server_socket));
assert(result != -1);
}
return 0;
}
client.cc
#include <arpa/inet.h>
#include <assert.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
pthread_t threads[4096];
char buffer[4096];
inline int send_all(int socket_fd, const char* data, size_t size, int flags)
{
int result;
const char* pos = data;
while (size > 0)
{
result = send(socket_fd, pos, size, flags);
assert(result > 0);
pos += result;
size -= result;
}
return 0;
}
inline int recv_all(int socket_fd, void* data, size_t size, int flags)
{
int result = recv(socket_fd, data, size, flags | MSG_WAITALL);
assert(((size_t) result) == size);
return 0;
}
void* client_thread(void* arg)
{
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
assert(socket_fd != -1);
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(11282);
server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
int result = connect(socket_fd,
(struct sockaddr *) &server_address,
sizeof(server_address));
assert(result != -1);
// send some info first
send_all(socket_fd, buffer, 1, 0);
// recv the reply data
for (int i = 0; i < 4096; i ++)
recv_all(socket_fd, buffer, sizeof(buffer), 0);
close(socket_fd);
return NULL;
}
int main(int argc, char* argv[])
{
assert(argc == 2);
// get client thread count
int thread_count = atoi(argv[1]);
assert(thread_count <= 4096);
for (int i = 0; i < thread_count; i ++)
{
int result = pthread_create(&threads[i], NULL, client_thread, NULL);
assert(result != -1);
}
for (int i = 0; i < thread_count; i ++)
pthread_join(threads[i], NULL);
return 0;
}
Usage:
./server
./client [thread_count]
I was using 480 as the thread_count, sometime I could reproduce the issue.
I have similar problem as here:
Netlink sockets and libnl - nl_recvmsgs_default returning -16 (EBUSY)
But nl_recvmsgs_defaul() return this error value -22 (NLE_MSGTYPE_NOSUPPORT).
Does anyone have an idea why I get this error?
Here is example program:
Kernel:
enum {
DOC_EXMPL_A_UNSPEC,
DOC_EXMPL_A_MSG,
__DOC_EXMPL_A_MAX,
};
#define DOC_EXMPL_A_MAX (__DOC_EXMPL_A_MAX - 1)
#define VERSION_NR 1
static struct genl_family doc_exmpl_gnl_family = {
.id = GENL_ID_GENERATE,
.hdrsize = 0,
.name = "CONTROL_EXMPL",
.version = VERSION_NR,
};
enum {
DOC_EXMPL_C_UNSPEC,
DOC_EXMPL_C_ECHO,
__DOC_EXMPL_C_MAX,
};
#define DOC_EXMPL_C_MAX (__DOC_EXMPL_C_MAX - 1)
int doc_exmpl_echo(struct sk_buff *skb_2, struct genl_info *info)
{
struct sk_buff *skb;
struct nlattr *na, *pos;
int len, rem, type, rc;
char * mydata;
void *msg_head;
if (info == NULL)
goto out;
len = nlmsg_attrlen(info->nlhdr, GENL_HDRLEN);
na = nlmsg_attrdata(info->nlhdr, GENL_HDRLEN);
printk(KERN_DEBUG "len1: %d, sizeof: %d ,len: %d", nlmsg_len(info->nlhdr),
GENL_HDRLEN, len);
nla_for_each_attr(pos, na, len, rem) {
type = nla_type(pos);
mydata = (char *) nla_data(pos);
printk(KERN_DEBUG "Type: %d", type);
if (mydata != NULL)
printk(KERN_DEBUG "Data: %s", mydata);
}
skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (skb == NULL)
goto out;
msg_head = genlmsg_put(skb, 0, info->snd_seq+1, &doc_exmpl_gnl_family, 0, DOC_EXMPL_C_ECHO);
if (msg_head == NULL) {
rc = -ENOMEM;
goto out;
}
rc = nla_put_u8(skb, DOC_EXMPL_A_MSG, 8);
if (rc != 0)
goto out;
/* finalize the message */
genlmsg_end(skb, msg_head);
//rc = genlmsg_unicast(skb,info->snd_pid );
rc = genlmsg_unicast(genl_info_net(info), skb,info->snd_pid);
if (rc != 0)
goto out;
printk(KERN_DEBUG "End");
return 0;
out:
printk("an error occured in doc_exmpl_echo:\n");
return 0;
}
struct genl_ops doc_exmpl_gnl_ops_echo = {
.cmd = DOC_EXMPL_C_ECHO,
.flags = 0,
.policy = NULL,
.doit = doc_exmpl_echo,
.dumpit = NULL,
};
Userspace code
#include <stdio.h>
#include <stdlib.h>
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <netlink/socket.h>
#include <netlink/msg.h>
#include <net/if.h>
static int expectedId;
static int nlCallback(struct nl_msg* msg, void* arg)
{
struct nlmsghdr* ret_hdr = nlmsg_hdr(msg);
struct nlattr *tb_msg[2 + 1];
char *str;
if (ret_hdr->nlmsg_type != expectedId)
{
// what is this??
return NL_STOP;
}
struct genlmsghdr *gnlh = (struct genlmsghdr*) nlmsg_data(ret_hdr);
nla_parse(tb_msg, 2, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
if (tb_msg[1]) {
str = nla_get_string(tb_msg[1]);
printf("str: %s", str);
}
return 0;
}
int main(int argc, char **argv) {
int cmd, rc;
struct nl_handle *sk;
struct nl_msg *msg;
//allocate socket
sk = nl_handle_alloc();
//connect to generic netlink
genl_connect(sk);
//find the nl80211 driver ID
expectedId = genl_ctrl_resolve(sk, "CONTROL_EXMPL");
//allocate a message
msg = nlmsg_alloc();
cmd = 1;
int flags = 0;
// setup the message
genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, expectedId, 0, NLM_F_REQUEST, cmd, 1);
NLA_PUT_STRING(msg, 3, "Hello test");
nl_send_auto_complete(sk, msg);
nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM,
nlCallback, NULL);
rc = nl_recvmsgs_default(sk);
printf("rc = %d \n", rc);
nlmsg_free(msg);
return 0;
nla_put_failure:
nlmsg_free(msg);
return 1;
}
OK I found the problem.
I have bad sequencer number in kernel code, it should be:
genlmsg_put(skb, 0, info->snd_seq, &doc_exmpl_gnl_family, 0, DOC_EXMPL_C_ECHO);
It's the same problem as here: Netlink sockets and libnl - nl_recvmsgs_default returning -16 (EBUSY) but I got other error.
so... context: I'm doing a layer 2 protocol for flexible forwarding in vehicular environment (for now my testbed is in virtual machines), this should take in consideration a different number of interfaces (for multihoming) and multihop.
So what I have:
A way of broadcasting hop-by-hop the service provider.
What I'm triyng to do:
A way to register a session all the way from the client to the provider (And here is the problem)
Problem: I have two types of packets
1st is listened correctly and data payload starts with a 1
2nd for some reason is not detected but I can see the packet is sent and correct with tcpdump
Since I have to register in the application the interface where the connection is made I used select() which seems to be part of the problem since I only guessed how it was used and I'm kind of in the dark about this.
UPDATED v3:
Okay so as soon as I removed most of the stuff about only sending on a specific interface all the stuff worked perfectly (I still need to clean this code... it's kind of messy). Here is code if someone is interested:
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <ifaddrs.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#define ETH_P_CUSTOM 0x0801 /* EtherType of Current Used Protocol*/
#define BUF_SIZE 1024
typedef enum {
false, true
} Bool; /* Boolean Definition*/
typedef struct Stat {
uint8_t maxSocket; /*Number of sockets to use in receive*/
uint8_t nInterfaces; /*Number of interfaces owned by this machine*/
uint8_t nSession; /*Number of Sessions Known in the linked list*/
uint8_t upMac[ETH_ALEN]; /*MAC of this host upstream parent*/
uint8_t nHops; /*Hops to Provider*/
char ifName[IF_NAMESIZE + 1]; /*Interface to Provider*/
} Stat;
typedef struct Node {
uint64_t session; /*Client Session*/
uint8_t nextHop[ETH_ALEN]; /*Next-Hop to Client*/
char ifName[IF_NAMESIZE + 1]; /*Outgoing Interface that connects to Next-Hop*/
struct Node * next; /*Next Session*/
} Node;
typedef struct ifNode {
uint8_t ifIndex; /*Interface index*/
uint8_t sock; /*Index in array of sockets*/
uint8_t mac[ETH_ALEN]; /*Interface MAC*/
char ifName[IF_NAMESIZE + 1]; /*Interface Name*/
struct ifNode * next; /*Next Session*/
} ifNode;
Stat * op; /* Variable which tracks status of certain structures/variables*/
Node * first = NULL, *last = NULL; /* Edges of linked list */
ifNode * iffirst = NULL, *iflast = NULL; /* Edges of interface linked list */
int cargc;
char **cargv;
int receiveP();
int broadServ();
int announceSelf();
Node* create(uint64_t sess, uint8_t n[ETH_ALEN], char interface[IF_NAMESIZE]);
void insert_node(Node * p);
Node* search(uint64_t session);
void update(uint64_t session, Node * p);
ifNode* createif(uint8_t idx, uint8_t sock, uint8_t ifmac[ETH_ALEN],
char interface[IF_NAMESIZE]);
void insert_ifnode(ifNode * p);
ifNode* searchif(uint8_t idx, uint8_t mode);
void updateif(uint8_t idx, ifNode * p);
void display();
void displayif();
void ctrlcoverride(int sig) {
printf("\nCtrl-C - Signal Caught - Exiting\n\n");
printf(
"Current Upstream MAC: %02x:%02x:%02x:%02x:%02x:%02x - NHops : %u - At Interface %s\n\n",
op->upMac[0], op->upMac[1], op->upMac[2], op->upMac[3],
op->upMac[4], op->upMac[5], op->nHops, op->ifName);
display();
exit(EXIT_SUCCESS);
}
Node* create(uint64_t sess, uint8_t n[ETH_ALEN], char interface[IF_NAMESIZE]) {
Node * new = (Node *) malloc(sizeof(Node));
if (new == NULL) {
printf("Could not create new node\n");
return NULL;
} else {
strcpy(new->ifName, interface);
new->session = sess;
int i;
for (i = 0; i < ETH_ALEN; i++)
new->nextHop[i] = n[i];
new->next = NULL;
return new;
}
}
ifNode* createif(uint8_t idx, uint8_t sock, uint8_t ifmac[ETH_ALEN],
char interface[IF_NAMESIZE]) {
ifNode * new = (ifNode *) malloc(sizeof(ifNode));
if (new == NULL) {
printf("Could not create new interface node\n");
return NULL;
} else {
new->ifIndex = idx;
new->sock = sock;
strcpy(new->ifName, interface);
int i;
for (i = 0; i < ETH_ALEN; i++)
new->mac[i] = ifmac[i];
new->next = NULL;
return new;
}
}
void insert_node(Node * p) {
if (first == last && last == NULL) {
first = last = p;
first->next = NULL;
last->next = NULL;
} else {
last->next = p;
last = last->next;
last->next = NULL;
}
}
void insert_ifnode(ifNode * p) {
if (iffirst == iflast && iflast == NULL) {
iffirst = iflast = p;
iffirst->next = NULL;
iflast->next = NULL;
} else {
iflast->next = p;
iflast = iflast->next;
iflast->next = NULL;
}
}
Node* search(uint64_t session) {
if (first == last && last == NULL) {
return NULL;
} else {
Node * temp;
for (temp = first; temp != NULL; temp = temp->next) {
if (temp->session == session) {
return temp;
}
}
return NULL;
}
}
ifNode* searchif(uint8_t idx, uint8_t mode) {
if (iffirst == iflast && iflast == NULL) {
return NULL;
} else {
ifNode * temp;
for (temp = iffirst; temp != NULL; temp = temp->next) {
if (temp->ifIndex == idx && mode == 0) {
return temp;
} else if (temp->sock == idx && mode == 1) {
return temp;
}
}
return NULL;
}
}
void update(uint64_t session, Node * p) {
if (first == last && last == NULL) {
return;
} else {
Node * temp;
for (temp = first; temp != NULL; temp = temp->next) {
if (temp->session == session) {
strcpy(temp->ifName, p->ifName);
temp->next = p->next;
int i;
for (i = 0; i < ETH_ALEN; i++)
temp->nextHop[i] = p->nextHop[i];
return;
}
}
}
}
void updateif(uint8_t idx, ifNode * p) {
if (iffirst == iflast && iflast == NULL) {
return;
} else {
ifNode * temp;
for (temp = iffirst; temp != NULL; temp = temp->next) {
if (temp->ifIndex == idx) {
strcpy(temp->ifName, p->ifName);
temp->sock = p->sock;
temp->next = p->next;
int i;
for (i = 0; i < ETH_ALEN; i++)
temp->mac[i] = p->mac[i];
return;
}
}
}
}
void display() {
Node * temp = first;
while (temp != NULL) {
printf("Session %" PRIu64 " Through %s - NextHop at ", temp->session,
temp->ifName);
int i;
for (i = 0; i < ETH_ALEN; i++)
printf("%02x ", temp->nextHop[i]);
printf("\n");
temp = temp->next;
}
}
void displayif() {
ifNode * temp = iffirst;
while (temp != NULL) {
printf("Interface Index %u Socket Number %u - Name %s with MAC: ",
temp->ifIndex, temp->sock, temp->ifName);
int i;
for (i = 0; i < ETH_ALEN; i++)
printf("%02x ", temp->mac[i]);
printf("\n");
temp = temp->next;
}
}
uint8_t counter() {
Node * temp = first;
uint8_t counter = 0;
while (temp != NULL) {
counter++;
temp = temp->next;
}
return counter;
}
fd_set rfds;
int rec;
int main(int argc, char **argv) {
setbuf(stdout, NULL);
signal(SIGINT, ctrlcoverride);
cargc = argc;
cargv = argv;
/*Setting Base Variables to Initial Values*/
op = (Stat*) malloc(sizeof(Stat));
op->nSession = 0;
memset(op->ifName, 0, IF_NAMESIZE);
op->maxSocket = 0;
op->nHops = UINT8_MAX - 1;
int i;
for (i = 0; i < ETH_ALEN; i++) {
op->upMac[i] = 0x00;
}
memset(&rfds, 0, sizeof(fd_set));
FD_ZERO(&rfds);
if (argc != 2) {
printf("USAGE: sudo %s {provider|node|nodekey}\n", cargv[0]);
exit(EXIT_FAILURE);
} else if (!(strcmp(cargv[1], "provider") == 0
|| strcmp(cargv[1], "node") == 0 || strcmp(cargv[1], "nodekey") == 0)) {
printf("USAGE: sudo %s {provider|node|nodekey}\n", cargv[0]);
exit(EXIT_FAILURE);
}
if (strcmp(cargv[1], "nodekey") == 0) {
srand(time(NULL));
uint8_t myArray[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
insert_node(
create((uint64_t) (100 * ((float) rand() / RAND_MAX)), myArray,
"SOURCE"));
}
struct ifaddrs *ifaddr, *ifa;
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
for (ifa = ifaddr, op->nInterfaces = 0; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
if (ifa->ifa_addr->sa_family == AF_PACKET
&& strncmp(ifa->ifa_name, "lo", strlen("lo")) != 0
&& strncmp(ifa->ifa_name, "tap", strlen("tap")) != 0) {
op->nInterfaces++;
}
}
rec = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_CUSTOM));
int sockopt;
char ifName[IFNAMSIZ];
struct ifreq ifr;
for (i = 1, ifa = ifaddr; ifa != NULL;
ifa = ifa->ifa_next, i++) {
if (ifa->ifa_addr == NULL)
continue;
if (ifa->ifa_addr->sa_family == AF_PACKET
&& strncmp(ifa->ifa_name, "lo", strlen("lo")) != 0
&& strncmp(ifa->ifa_name, "tap", strlen("tap")) != 0) {
uint8_t sock;
if ((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_CUSTOM)))
== -1) {
printf("socket() error: %u - %s\n", errno, strerror(errno));
return EXIT_FAILURE;
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sockopt,
sizeof sockopt) == -1) {
printf("SO_REUSEADDR error: %u - %s\n", errno, strerror(errno));
close(sock);
return EXIT_FAILURE;
}
memset(&ifr, 0, sizeof(struct ifreq));
ifr.ifr_ifindex = i;
strcpy(ifr.ifr_name, ifa->ifa_name);
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifa->ifa_name,
IF_NAMESIZE) == -1) {
printf("SO_BINDTODEVICE error: %u - %s\n", errno,
strerror(errno));
close(sock);
return EXIT_FAILURE;
}
struct sockaddr_ll sll;
sll.sll_family = AF_PACKET;
sll.sll_ifindex = i;
sll.sll_protocol = htons(ETH_P_CUSTOM);
if ((bind(sock, (struct sockaddr *) &sll, sizeof(sll))) == -1) {
perror("Error binding raw socket to interface\n");
exit(-1);
}
if ((ioctl(sock, SIOCGIFHWADDR, &ifr)) != 0) {
printf("SIOCGIFHWADDR error: %u - %s\n", errno,
strerror(errno));
return EXIT_FAILURE;
}
int j;
uint8_t ifmac[ETH_ALEN];
for (j = 0; j < ETH_ALEN; j++) {
ifmac[j] = (uint8_t) (ifr.ifr_hwaddr.sa_data)[j];
}
FD_SET(sock, &rfds);
op->maxSocket = (op->maxSocket < sock) ? sock : op->maxSocket;
insert_ifnode(createif(i, sock, ifmac, ifr.ifr_name));
}
}
displayif();
if (strcmp(cargv[1], "provider") == 0) {
struct ifreq if_mac; // interface
char * interface = "eth1";
int sockfd;
if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_CUSTOM))) == -1) {
printf("socket() error: %u - %s\n", errno, strerror(errno));
return EXIT_FAILURE;
}
memset(&if_mac, 0, sizeof(struct ifreq));
strncpy(if_mac.ifr_name, interface, IFNAMSIZ - 1);
if ((ioctl(sockfd, SIOCGIFHWADDR, &if_mac)) != 0) {
printf("SIOCGIFHWADDR error: %u - %s\n", errno, strerror(errno));
return EXIT_FAILURE;
}
int i;
for (i = 0; i < ETH_ALEN; i++)
op->upMac[i] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[i];
op->nHops = 0;
close(sockfd);
}
freeifaddrs(ifaddr);
int stat = 0;
while (1) {
if (strcmp(cargv[1], "provider") == 0) {
if ((stat = receiveP()) != 0)
return stat;
if ((stat = broadServ()) != 0)
return stat;
display();
usleep(100000);
} else if (strcmp(cargv[1], "node") == 0
|| strcmp(cargv[1], "nodekey") == 0) {
if ((stat = receiveP()) != 0)
return stat;
if ((stat = announceSelf()) != 0){
return stat;
}
if ((stat = broadServ()) != 0)
return stat;
display();
usleep(100000);
}
}
ifNode * temp = iffirst;
while (temp != NULL) {
close(temp->sock);
temp = temp->next;
}
exit(stat);
}
int receiveP() {
int stat = 0;
struct ifreq ifr;
struct sockaddr saddr;
long unsigned int numbytes = 0;
char buf[BUF_SIZE];
memset(buf, 0, BUF_SIZE);
struct ether_header *eh = (struct ether_header *) buf;
unsigned int saddr_size = sizeof saddr;
struct timeval tv;
tv.tv_sec = 3; /* 3 Secs Timeout */
tv.tv_usec = 0;
setsockopt(rec, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv,
sizeof(struct timeval));
numbytes = recvfrom(rec, buf, BUF_SIZE, 0, &saddr, &saddr_size);
int len;
int ntable;
switch (buf[sizeof(struct ether_header)]) {
case 1:
if (buf[sizeof(struct ether_header) + 1] < op->nHops) {
op->upMac[0] = eh->ether_shost[0];
op->upMac[1] = eh->ether_shost[1];
op->upMac[2] = eh->ether_shost[2];
op->upMac[3] = eh->ether_shost[3];
op->upMac[4] = eh->ether_shost[4];
op->upMac[5] = eh->ether_shost[5];
op->nHops = buf[sizeof(struct ether_header) + 1] + 1;
memset(&ifr, 0, sizeof(struct ifreq));
memset(&ifr.ifr_name, 0, IF_NAMESIZE);
printf(
"Server %u Hops Away - Through %02x:%02x:%02x:%02x:%02x:%02x At Interface %s\n",
op->nHops, eh->ether_shost[0], eh->ether_shost[1],
eh->ether_shost[2], eh->ether_shost[3], eh->ether_shost[4],
eh->ether_shost[5], op->ifName);
printf("\n\n");
}
break;
case 2:
len = sizeof(struct ether_header) + 1;
ntable = buf[len++];
int j;
for (j = 0; j < ntable; j++, len++) {
if (search(buf[len]) == NULL) {
insert_node(create(buf[len], eh->ether_shost, ""));
}
}
break;
}
return stat;
}
int broadServ() {
int stat = 0;
int tx_len = 0;
char sendbuf[BUF_SIZE];
char ifName[IF_NAMESIZE - 1];
struct ether_header *eh = (struct ether_header *) sendbuf;
struct sockaddr_ll socket_address;
int i;
struct ifreq ifr, if_mac;
ifNode * temp = iffirst;
while (temp != NULL) {
/* Get the index of the interface to send on */
memset(&ifr, 0, sizeof(struct ifreq));
ifr.ifr_ifindex = temp->ifIndex;
if (ioctl(temp->sock, SIOCGIFNAME, &ifr) < 0)
perror("SIOCGIFINDEX");
memset(ifName, 0, IF_NAMESIZE - 1);
strncpy(ifName, ifr.ifr_name, IF_NAMESIZE - 1);
/* Get the MAC address of the interface to send on */
memset(&if_mac, 0, sizeof(struct ifreq));
strncpy(if_mac.ifr_name, ifName, IFNAMSIZ - 1);
if (ioctl(temp->sock, SIOCGIFHWADDR, &if_mac) < 0)
perror("SIOCGIFHWADDR");
if (((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[0] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[1] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[2] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[3] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[4] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[5] == 0x00)
continue;
memset(sendbuf, 0, BUF_SIZE);
/* Ethernet header */
eh->ether_shost[0] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[0];
eh->ether_shost[1] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[1];
eh->ether_shost[2] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[2];
eh->ether_shost[3] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[3];
eh->ether_shost[4] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[4];
eh->ether_shost[5] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[5];
eh->ether_dhost[0] = 0xff;
eh->ether_dhost[1] = 0xff;
eh->ether_dhost[2] = 0xff;
eh->ether_dhost[3] = 0xff;
eh->ether_dhost[4] = 0xff;
eh->ether_dhost[5] = 0xff;
/* Ethertype field */
eh->ether_type = htons(ETH_P_CUSTOM);
tx_len = sizeof(struct ether_header);
/* Packet data */
sendbuf[tx_len++] = 1;
sendbuf[tx_len++] = op->nHops; //+1;
/* Index of the network device */
socket_address.sll_ifindex = temp->ifIndex;
/* Address length*/
socket_address.sll_halen = ETH_ALEN;
/* Destination MAC */
socket_address.sll_addr[0] = 0xff;
socket_address.sll_addr[1] = 0xff;
socket_address.sll_addr[2] = 0xff;
socket_address.sll_addr[3] = 0xff;
socket_address.sll_addr[4] = 0xff;
socket_address.sll_addr[5] = 0xff;
/* Send packet */
if (sendto(temp->sock, sendbuf, tx_len, 0,
(struct sockaddr*) &socket_address, sizeof(struct sockaddr_ll))
< 0)
printf("Send failed\n");
temp = temp->next;
}
return stat;
}
int announceSelf() {
if (op->upMac[0] == 0x00 && op->upMac[1] == 0x00 && op->upMac[2] == 0x00
&& op->upMac[3] == 0x00 && op->upMac[4] == 0x00
&& op->upMac[5] == 0x00)
return EXIT_SUCCESS;
int stat = 0;
int tx_len = 0;
char sendbuf[BUF_SIZE];
char ifName[IF_NAMESIZE - 1];
struct ether_header *eh = (struct ether_header *) sendbuf;
struct sockaddr_ll socket_address;
int i;
struct ifreq ifr, if_mac;
ifNode * temp = iffirst;
while (temp != NULL) {
memset(&ifr, 0, sizeof(struct ifreq));
ifr.ifr_ifindex = temp->ifIndex;
if (ioctl(temp->sock, SIOCGIFNAME, &ifr) < 0)
perror("SIOCGIFINDEX");
memset(ifName, 0, IF_NAMESIZE - 1);
strncpy(ifName, ifr.ifr_name, IF_NAMESIZE - 1);
/* Get the MAC address of the interface to send on */
memset(&if_mac, 0, sizeof(struct ifreq));
strncpy(if_mac.ifr_name, ifName, IFNAMSIZ - 1);
if (ioctl(temp->sock, SIOCGIFHWADDR, &if_mac) < 0)
perror("SIOCGIFHWADDR");
if (((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[0] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[1] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[2] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[3] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[4] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[5] == 0x00)
continue;
memset(sendbuf, 0, BUF_SIZE);
/* Ethernet header */
eh->ether_shost[0] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[0];
eh->ether_shost[1] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[1];
eh->ether_shost[2] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[2];
eh->ether_shost[3] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[3];
eh->ether_shost[4] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[4];
eh->ether_shost[5] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[5];
eh->ether_dhost[0] = op->upMac[0];
eh->ether_dhost[1] = op->upMac[1];
eh->ether_dhost[2] = op->upMac[2];
eh->ether_dhost[3] = op->upMac[3];
eh->ether_dhost[4] = op->upMac[4];
eh->ether_dhost[5] = op->upMac[5];
/* Ethertype field */
eh->ether_type = htons(ETH_P_CUSTOM);
tx_len = sizeof(struct ether_header);
/* Packet data */
sendbuf[tx_len++] = 2;
sendbuf[tx_len++] = counter();
Node *temp1 = first;
for (; temp1 != NULL; temp1 = temp1->next) {
sendbuf[tx_len++] = temp1->session;
}
socket_address.sll_ifindex = temp->ifIndex;
/* Address length*/
socket_address.sll_halen = ETH_ALEN;
/* Destination MAC */
socket_address.sll_addr[0] = op->upMac[0];
socket_address.sll_addr[1] = op->upMac[1];
socket_address.sll_addr[2] = op->upMac[2];
socket_address.sll_addr[3] = op->upMac[3];
socket_address.sll_addr[4] = op->upMac[4];
socket_address.sll_addr[5] = op->upMac[5];
/* Send packet */
if (sendto(temp->sock, sendbuf, tx_len, 0,
(struct sockaddr*) &socket_address, sizeof(struct sockaddr_ll))
< 0)
printf("Send failed\n");
temp = temp->next;
}
return stat;
}
So to test this you can have VM with linux connected like this (for example):
Provider ----- Node ----- Node ----- Nodekey
I still had a problem when creating multiple sessions, i wasn't incrementing the buffer when reading and I was reading multiple times the same position. Now it's working good
OK, let's begin with the easiest recommendations but I'm not sure this is going to resolve the problem at once. I did a system like this many years ago for different boards with different processor architectures communicating with each other. All the boards were running within a telecommunication switch. It's a very nice problem and you are facing it in the proper way with a peer-to-peer distributed solution.
I didn't go through all code but it seems each node is discovering the neighbour nodes in the network and everyone is creating a tree.
In select, the first argument should not be FD_SETSIZE but the highest-numbered file descriptor in any of the three sets (in this case the read set), plus 1.
The infinite loop is calling receiveSession which is creating all sockets again and then it reads. If a frame with your specific layer-2 protocol arrives in the middle and there is no socket listening for it, it will be discarded. Maybe your problem could be here.
When you send Ethernet frames directly, the hardware will complete the frame to the minimum Ethernet size: 64 octets (so you might receive padding data up to 46 octets - Octets not Bytes)
Please read here:
http://en.wikipedia.org/wiki/Ethernet_frame
It is good you chose an EtherType ETH_P_CUSTOM higher than 1536 that is not already in use but maybe you want to use a much higher number in order to minimize possibilities of collision with other protocols.
Something important. Your testbed now is with VM's which are usually x86 architectures, 64 bits. When you run your software in real devices with different processors, that might not be the situation. This is very important because you might have different architectures with different endianship and different integer size. That will affect the integer numbers you send, especially in ether_header, and the size of your structures. You have to use the the macros ntohs, ntohl, htons, htonl to change between host and network endianship (session is uint64_t). You should send data in network endianship. This is not solving your very current problem but you might have this problem in the future.