Can I implement client - client communication through server in between? - c

I want to send message from client A to client B, through this server. I am not sure how can I get that? One approach I can think of is making a message queue for each client and add message to that queue if someone sends message to that client, and sends from that queue to the respective client ? But I am not sure How can I implement this ? Can anyone help me with this ?
There can be n clients at any moments. In that case broadcast to all clients.
Below is my server code. I have checked username and password of the user. insidePortal() function will take care of sending message to other client.
#include<stdio.h>
#include <stdlib.h>
#include<string.h> //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h> //write
int main(int argc , char *argv[])
{
int socket_desc , client_sock , c , read_size, pid;
struct sockaddr_in server , client;
char client_message[2000], message_sent[2000], message_recieve[2000];
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 5550 );
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 3);
while (1) {
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
// accept connection from an incoming client
client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (client_sock < 0)
{
perror("accept failed");
return 1;
}
/* Create child process */
pid = fork();
if (pid == 0) {
/* This is the client process */
close(socket_desc);
puts("Connection accepted");
char username[50], password[50];
memset(message_recieve, 0, sizeof message_recieve);
recv(client_sock , username , 2000 , 0);
printf("username of the user: %s", username);
memset(message_recieve, 0, sizeof message_recieve);
recv(client_sock , password , 2000 , 0);
printf("password of the user: %s", password);
FILE *f = fopen("registeredUsers.txt", "r");
if (f == NULL)
{
printf("Error opening file!\n");
exit(1);
}
char uname[50], pass[50];
int login = 0;
while(fscanf(f, "%s %s\n", uname, pass) > 0) {
printf("Helllo %s %s", uname, pass);
if (strcmp(username, uname)==0 && strcmp(password, pass) == 0) {
login = 1;
break;
}
}
memset(message_sent, 0, sizeof message_sent);
if (login == 1) {
strcpy(message_sent,"\n Successfull Login\n");
write(client_sock , message_sent , strlen(message_sent)); // Sends login status
insidePortal(client_sock, username);
} else {
strcpy(message_sent,"\nOops, wrong username or password. Please try again.\n");
write(client_sock , message_sent , strlen(message_sent)); // Sends login status
}
fclose(f);
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
exit(0);
} else {
close(client_sock);
}
}
return 0;
}
void insidePortal(int client_sock, char username[50]) {
}

I have this really long code I've wrote in the past that implements something similar to yours, but It's CPP, If you want too I'll post it here, but basically using message queues or multi-process programming seems kinda useless to me, If I were you I'd program it in the following way
Client code -> Two Threads
Server code -> Two Threads
Client Has two threads, and Three functions, Connect / Send / Receive
Connect - This function handles connection to server, whether you are using TCP it handles the listen-accept or if you use some UDP based made up protocol, it just handles it - makes sure you have some connectin
Send - This function sends some data to server
Receive This functino receives data from server
The flow of Client would be the following:
Client connects to server on Main thread
After connecting to server Client creates Second thread
On Main thread - Client enters some loop that reads data from user as Input then calls Send function and sends it to server
On Second thread - Client enters some loop that calls Receive
to receive data from server and prints it when data is received
that handles Client, now about Server
Server- Has Three functions and Some one Global data structure called Linked - List ( a Linked list obviously ) that would be shared by all it's threads, WaitForConnection Receive SendToAll
WaitForConnection- Simply calls the "Accept" function of sockets API ( if you're using TCP ) or if you're using some other made up protocol, this function just blocks it's thread as trying to wait for incoming connection, when some connection arrives, this function registers the connection into the global linked-list of all connections called Connection-List, with the appropriate socket and client data
SendToAll - Simply iterates all Connection-List and for every Connection within that list, It sends some data passed
Receive just receives some data but sets some timeout first, this is very important in order for Receive not to block for too long!
The flow of Server would be the following:
Main thread creats Second thread
Main thread enters some loop and calls WaitForConnection within it in order to continuously get connections and add them into Connection-List
Second thread enters some loop that iterates over Connection-List, for each connection within Connection-List, receive is called upon the appropriate socket, if some data is receive, SendToAll is called with the data received, if timeout, nothing happens, after that loop is continued and the next loop iteration is executed
SendToAll sends the data to ALL clients within Connection-List
This is some very simple Multi-Client Broadcast with Server architecture It should be really easy to implement! I hope this helps you
I Apologize in advance as this is a code I wrote a while ago so It has a lot of nesting within it, and a lot of comments!
------------------------- CLIENT CODE ----------------
// Main.cpp
#include <thread>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#pragma comment (lib, "Ws2_32.lib")
#define NAME_LENGTH 40
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "8888"
void Receive(SOCKET* pscktConnection);
void Send(SOCKET* pscktConnection);
void main()
{
// Variable definition
int nResult;
int nNameLength = 0;
char pcNameBuffer[NAME_LENGTH];
SOCKET sckConnection = NULL;
WSADATA wsaData;
addrinfo addrAddressFormat;
addrinfo* paddrServerAddress;
// Code section
// Initialize Winsock
nResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
// If winsock dll loading has failed
if (nResult != 0)
{
std::cout << "Failed loading winsock DLL" << std::endl;
}
// DLL loaded successfully
else
{
//Setup connection info
ZeroMemory(&addrAddressFormat, sizeof(addrAddressFormat));
addrAddressFormat.ai_family = AF_INET;
addrAddressFormat.ai_socktype = SOCK_STREAM;
addrAddressFormat.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port with the address setting into our final address
nResult = getaddrinfo("10.0.0.5", DEFAULT_PORT, &addrAddressFormat, &paddrServerAddress);
// Address resolving has failed
if (nResult != 0)
{
std::cout << "Some error has occured during connection establishment" << std::endl;
}
else
{
// Request user for his name
pcNameBuffer[0] = '\0';
std::cout << "PLEASE ENTER YOUR NAME -> ";
std::cin.getline(pcNameBuffer, NAME_LENGTH);
std::cout << std::endl << std::endl ;
// Creating the socket
sckConnection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Connecting
nResult = connect(sckConnection, paddrServerAddress->ai_addr, (int)paddrServerAddress->ai_addrlen);
// Creating of the socket has failed
if (nResult == SOCKET_ERROR)
{
std::cout << "Creating of the socket has failed" << std::endl;
}
// Send server user's name
else
{
// Measure the name length
while (pcNameBuffer[nNameLength] != '\0')
{
++nNameLength;
}
// If invalid name
if (nNameLength == 0)
{
pcNameBuffer[0] = 'G';
pcNameBuffer[1] = 'U';
pcNameBuffer[2] = 'E';
pcNameBuffer[3] = 'S';
pcNameBuffer[4] = 'T';
pcNameBuffer[5] = '\0';
nNameLength = 6;
}
nResult = send(sckConnection, pcNameBuffer, nNameLength + 1, 0);
// An error has occured while sending server the user's name
if (nResult <= 0)
{
std::cout << "Some error has occured" << std::endl;
}
// Good to go
else
{
std::thread Read(Receive, &sckConnection);
Send(&sckConnection);
}
}
}
}
// cleanup resources
WSACleanup();
}
/*
* [Description]: This method is used only to read messages from server and print them
* [Paramaters]:
* pscktServerSocket - The address of the our connection socket
* [Return Value]: none
*/
void Receive(SOCKET* pscktConnection)
{
// Variable definition
int nReceivedBytes;
int nBufferLen = DEFAULT_BUFLEN;
char pcBuffer[DEFAULT_BUFLEN];
// Code section
// Keep this operation running constantly
while (true)
{
// Read from server -- NO TIME OUT NEEDED
nReceivedBytes = recv((*pscktConnection), pcBuffer, nBufferLen, 0);
// More than zero bytes received
if (nReceivedBytes > 0)
{
// Set a zero termination to simulate a string
pcBuffer[nReceivedBytes] = '\0';
std::cout << pcBuffer << std::endl;
}
// Server has closed the connection probably
else
{
// TODO - CLOSE CONNECTION
}
}
}
/*
* [Description]: This method is used only to send messages to the server
* [Paramaters]:
* pscktServerSocket - The address of the our connection socket
* [Return Value]: none
*/
void Send(SOCKET* pscktConnection)
{
// Variable definition
int nSentBytes;
int nBufferLen = DEFAULT_BUFLEN;
char pcBuffer[DEFAULT_BUFLEN];
// Code section
pcBuffer[0] = '\0';
// Keep this operation running constantly
while (true)
{
int nSentBytes = 0;
// Read
std::cin.getline(pcBuffer, nBufferLen);
// Go through string untill backslash 0
while (pcBuffer[nSentBytes] != '\0')
{
// Increase the number of bytes we want to send
++nSentBytes;
}
pcBuffer[nSentBytes] = '\0';
nSentBytes = send((*pscktConnection), pcBuffer, nSentBytes, 0);
// An error has occured
if (nSentBytes == SOCKET_ERROR)
{
// TODO - HANDLE ERROR;
}
}
}
`
------------------------- SERVER CODE ----------------
// Source.cpp
#include <thread>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include "Client.h"
#include "Connections.h"
#pragma comment (lib, "Ws2_32.lib")
#define NAME_LENGTH 40
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "8888"
#define MAX_CONNECTIONS 5
// Globals
Connections* conAllConnections = Connections::getInstance();
bool LoadServerSocket(SOCKET* pscktServerSocket);
void Dispatcher(SOCKET* pscktServerSocket);
void SendAll(ClientNode* pclndSenderAddress, char* pcMessageBuffer, int nLength);
void HandleConnections();
void main()
{
// Variable definition
int nResult;
SOCKET sckServerSocket = NULL;
WSADATA wsaData;
// Code section
// Initialize Winsock
nResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
// If winsock dll loading has failed
if (nResult != 0)
{
std::cout << "Failed loading winsock DLL" << std::endl;
}
// DLL loaded successfully
else
{
// If failed loading the server socket
if (!LoadServerSocket(&sckServerSocket))
{
std::cout << "Failed loading the server socket!" << std::endl;
}
else
{
std::thread dispatch(Dispatcher,&sckServerSocket);
//dispatch.join();
HandleConnections();
}
}
// cleanup resources
WSACleanup();
}
/*
* [Description]: This method is used to load and bind server socket into some pointer.
* [Paramaters]:
* pscktServerSocket - a pointer variable that we would like to load our socket into the address this pointer
* is pointing at
* [Return Value]: A boolean indication of whether our socket was created successfully
*/
bool LoadServerSocket(SOCKET* pscktServerSocket)
{
// Variable definition
int nResult;
bool bWasServerSocketCreated = false;
bool bWasAddressResolved = false;
addrinfo addrAddressFormat;
addrinfo* paddrFinalAddress = NULL;
// Code section
// Fil addrAddressFormat with zeros, and set correct settings of our desired socket
ZeroMemory(&addrAddressFormat, sizeof(addrAddressFormat));
addrAddressFormat.ai_family = AF_INET;
addrAddressFormat.ai_socktype = SOCK_STREAM;
addrAddressFormat.ai_protocol = IPPROTO_TCP;
//addrAddressFormat.ai_flags = AI_PASSIVE;
// Resolve the server address and port with the address setting into our final address
nResult = getaddrinfo("10.0.0.5", DEFAULT_PORT, &addrAddressFormat, &paddrFinalAddress);
// If resolving of the address was successful
if (nResult == 0)
{
// Set address resolving bool indication to true
bWasAddressResolved = true;
// Create server socket
(*pscktServerSocket) = socket(paddrFinalAddress->ai_family,
paddrFinalAddress->ai_socktype,
paddrFinalAddress->ai_protocol);
// Socket creating was successful
if ((*pscktServerSocket) != INVALID_SOCKET)
{
// Set socket creation indication to true
bWasServerSocketCreated = true;
// Bind our socket into our address
nResult = bind((*pscktServerSocket),
paddrFinalAddress->ai_addr,
(int)paddrFinalAddress->ai_addrlen);
// In case binding failed
if (nResult == SOCKET_ERROR)
{
closesocket((*pscktServerSocket));
bWasServerSocketCreated = false;
}
}
}
// Freeing resources
if (bWasAddressResolved)
{
freeaddrinfo(paddrFinalAddress);
}
return (bWasServerSocketCreated);
}
/*
* [Description]: This uses the loaded server socket and handles incoming requests for connections
* [Paramaters]:
* pscktServerSocket - a pointer to the loaded server socket
* [Return Value]: none
*/
void Dispatcher(SOCKET* pscktServerSocket)
{
// Variable definition
int nResult;
char pcBuffer[NAME_LENGTH];
DWORD timeout = 1500;
SOCKET sckClientSocket;
Client clntNewClient;
// Code section
// Keep this running constantly
while (true)
{
// Keep this running as long as we have the sufficient amount of connections
while (conAllConnections->getNumOfConnections() < MAX_CONNECTIONS)
{
// Attempt listening on the server socket
nResult = listen((*pscktServerSocket), MAX_CONNECTIONS);
// Listening was a failure
if (nResult == SOCKET_ERROR)
{
std::cout << "Failed listening with the server socket" << std::endl;
// HANDLE ERROR - TODO
}
// Listening was successful
else
{
std::cout << "Listening...." << std::endl;
// Accept a client socket
sckClientSocket = accept((*pscktServerSocket), NULL, NULL);
// Accepting was a failure
if (sckClientSocket == INVALID_SOCKET)
{
std::cout << "Client accepting has failed" << std::endl;
// HANDLE ERROR - TODO
}
// Client was added successfully
else
{
setsockopt(sckClientSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
nResult = recv(sckClientSocket, pcBuffer, NAME_LENGTH, 0);
// If received a valid username
if (nResult > 0)
{
timeout = 1;
std::cout << "New Client -> " << pcBuffer << std::endl;
clntNewClient.setClientSocket(sckClientSocket);
clntNewClient.setIsAdmin(false);
clntNewClient.setClientName(pcBuffer);
setsockopt(clntNewClient.getClientSocket(), SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
conAllConnections->Add(clntNewClient);
// Receive until the peer shuts down the connection
}
}
}
}
}
}
/*
* [Description]: This method forwards a message to all other clients but the client who sent it
* [Paramaters]:
* pclndSenderAddress - The address of the client node who sent the
* pcMessageBuffer- a pointer to the message buffer
* nLength - the length of the message
* [Return Value]: none
*/
void SendAll(ClientNode* pclndSenderAddress, char* pcMessageBuffer, int nLength)
{
// Variable definition
int nError;
int nResult;
Client clntCurrentClient;
ClientNode* pclndCurrentNode;
ClientNode* pclndNextNode;
// Code section
// Set first node
pclndCurrentNode = conAllConnections->getFirst();
// Go through all connections
while (pclndCurrentNode != NULL)
{
// Save the next node in this phase of the code in order to avoid corruption of memory
// in case node would be deleted from dynamic allocated memory and we wont be able to call the next val upon it
pclndNextNode = pclndCurrentNode->getNext();
// Compare addresses, we do not want to forward the message to the sender
if (pclndCurrentNode != pclndSenderAddress)
{
clntCurrentClient = pclndCurrentNode->getClient();
// Forward the message
nResult = send(clntCurrentClient.getClientSocket(), pcMessageBuffer, nLength, 0);
// An error has occured
if (nResult == SOCKET_ERROR)
{
nError = WSAGetLastError();
// TODO -- handle later
}
}
// Forward current node
pclndCurrentNode = pclndNextNode;
}
}
/*
* [Description]: This method handles and receives messages from our clients and forwards them
* [Paramaters]: none
* [Return Value]: none
*/
void HandleConnections()
{
// Variable definition
int nIndex;
int nError;
int nRecvLen;
int nNameLen;
int nRecvbuflen = DEFAULT_BUFLEN;
char pcBuffer[DEFAULT_BUFLEN + NAME_LENGTH + 3];
Client clntCurrentClient;
ClientNode* pclndCurrentNode;
ClientNode* pclndNextNode;
// Code section
// Keep this going constantly
while (true)
{
pclndCurrentNode = conAllConnections->getFirst();
// Go through all connections
while (pclndCurrentNode != NULL)
{
clntCurrentClient = pclndCurrentNode->getClient();
// Save the next node in this phase of the code in order to avoid corruption of memory
// in case node would be deleted from dynamic allocated memory and we wont be able to call the next val upon it
pclndNextNode = pclndCurrentNode->getNext();
// Attempt receiving data from client
nRecvLen = recv(clntCurrentClient.getClientSocket(), pcBuffer, nRecvbuflen, 0);
// An error has occured
if (nRecvLen <= 0)
{
nError = WSAGetLastError();
// if not a timeout error
if (nError != 10060)
{
std::cout << "Client removed" << std::endl;
// Socket error, remove connection
conAllConnections->Remove(pclndCurrentNode);
}
}
// No error has occured
else
{
//// The purpose of this part of the code is only to place a [CLIENTNAME]
//// prefix within the begining of each message
////--------------------------------////
// Get client's name length
nNameLen = clntCurrentClient.getNameLength();
nIndex = nRecvLen - 1;
// Copy the message some offset forward -- offset is (namn length + 4)
while (nIndex >= 0)
{
// Copy letter (namelen + 4) times forward
pcBuffer[nIndex + nNameLen + 4] = pcBuffer[nIndex];
// Reduce nIndex
--nIndex;
}
pcBuffer[0] = '[';
nIndex = 0;
// Place clients name within message
while (nIndex < nNameLen)
{
// + 1 for offset
pcBuffer[nIndex + 1] = (clntCurrentClient.getClientName())[nIndex];
// Increase nIndex
++nIndex;
}
pcBuffer[nIndex + 1] = ']';
pcBuffer[nIndex + 2] = ':';
pcBuffer[nIndex + 3] = ' ';
////--------------------------------////
//// No longer adding a prefix code
SendAll(pclndCurrentNode, pcBuffer, nRecvLen + nNameLen + 4);
}
// Forward current node
pclndCurrentNode = pclndNextNode;
}
}
}
////////////////////////////////////////////////////
// Connections.h
#ifndef CONNECTIONS_H
#define CONNECTIONS_H
#include "ClientNode.h"
class Connections
{
private:
// Data members
static Connections* _Instance;
int nNumOfConnections;
ClientNode* pclndFirst;
// Ctor
Connections();
public:
// Methods
void Add(Client clntNewClient);
void Remove(ClientNode* pclndClientToRemove);
int getNumOfConnections();
ClientNode* getFirst();
// Static methods
static Connections* getInstance();
};
#endif
////////////////////////////////////////////////////
// Connections.cpp
#include "Connections.h"
// Set instance to null
Connections* Connections::_Instance = NULL;
/* ------- PRIVATE CTOR -------
* [Description]: This method is the constructor of the Connections
* [Paramaters]: none
* [Return Value]: none
*/
Connections::Connections()
{
this->nNumOfConnections = 0;
this->pclndFirst = NULL;
}
/*
* [Description]: This method returns the amount of connections currently within our linked list
* [Paramaters]: none
* [Return Value]: The amount of connections
*/
int Connections::getNumOfConnections(){
return (this->nNumOfConnections);
}
/*
* [Description]: This method returns a pointer to the first client node within our connection list
* [Paramaters]: none
* [Return Value]: A pointer to the first client node
*/
ClientNode* Connections::getFirst()
{
return (this->pclndFirst);
}
/*
* [Description]: This method adds a new client to the linkedlist of clients
* [Paramaters]:
* clntNewClient - The new client struct
* [Return Value]: none
*/
void Connections::Add(Client clntNewClient)
{
// Create a new client node
ClientNode* pclndNewClientNode = new ClientNode;
// Set the client node's client
pclndNewClientNode->setClient(clntNewClient);
// Set the client node's next client pointer to point at the currenly first address
pclndNewClientNode->setNext(this->getFirst());
// Set the first client pointer to point at the new client node's address ( Push it within the linked list )
this->pclndFirst = pclndNewClientNode;
// Increase the number of connection
++(this->nNumOfConnections);
}
/*
* [Description]: This method removes a client from our linked list of connections
* [Paramaters]:
* pclndClientToRemove - The address of the client node we wish to remove
* [Return Value]: none
*/
void Connections::Remove(ClientNode* pclndClientToRemove){
// Variable definition
int nIndex;
ClientNode* pclndCurrentNode;
// Code section
pclndCurrentNode = this->getFirst();
// Checking if we need to remove the first node
if (pclndCurrentNode == pclndClientToRemove)
{
// Jump over deleted node
this->pclndFirst = pclndClientToRemove->getNext();
// Free memory
delete pclndClientToRemove;
// Decrease amount of connections
--(this->nNumOfConnections);
}
// We do not need to remove the first one
else
{
// Go through all ClientNodes addresses
for (nIndex = 0; nIndex < (this->nNumOfConnections - 1); ++nIndex)
{
// If the next node is the node we wish to delete
if (pclndCurrentNode->getNext() == pclndClientToRemove)
{
// Set the current node next node to be the next node of the node we wish to delete
pclndCurrentNode->setNext(pclndClientToRemove->getNext());
// free dynamically allocated memory
delete pclndClientToRemove;
// break outside the loop
break;
// Decrease amount of connections
--(this->nNumOfConnections);
}
// Next node is not the node we whish to delete
else
{
// Move to the next node
pclndCurrentNode = pclndCurrentNode->getNext();
}
}
}
}
/*
* [Description]: This method returns the only instance of Connections (SINGLETON PATTERN)
* [Paramaters]: none
* [Return Value]: A pointer to the single instance of connection
*/
Connections* Connections::getInstance(){
// If instance was not instantiated yet
if (_Instance == NULL)
{
// Call CTOR
_Instance = new Connections();
}
return (_Instance);
}
////////////////////////////////////////////////////
// ClientNode.h
#ifndef CLIENTNODE_H
#define CLIENTNODE_H
#include "Client.h"
class ClientNode
{
// Data members
Client clntClient;
ClientNode* pclntNextClient;
public:
// Access methods
void setNext(ClientNode* pclndNextNode);
void setClient(Client clntNewClient);
Client getClient();
ClientNode* getNext();
};
#endif
////////////////////////////////////////////////////
// ClientNode.cpp
#include "ClientNode.h"
/*
* [Description]: This method sets the next node our node would be pointing add
* [Paramaters]:
* pclndNextNode - The address of the next node we want this node to point at
* [Return Value]: none
*/
void ClientNode::setNext(ClientNode* pclndNextNode)
{
this->pclntNextClient = pclndNextNode;
}
/*
* [Description]: This method sets the client struct we want our current node to contain
* [Paramaters]:
* clntNewClient - New client
* [Return Value]: none
*/
void ClientNode::setClient(Client clntNewClient)
{
this->clntClient = clntNewClient;
}
/*
* [Description]: This method returns the client instance our node contains
* [Paramaters]: none
* [Return Value]: Our client
*/
Client ClientNode::getClient()
{
return (this->clntClient);
}
/*
* [Description]: This method returns the next node our node points at
* [Paramaters]: none
* [Return Value]: The address of the next node this node is pointing at
*/
ClientNode* ClientNode::getNext()
{
return (this->pclntNextClient);
}
////////////////////////////////////////////////////
// Client.h
#ifndef CLIENT_H
#define CLIENT_H
#include <WinSock2.h>
#define MAX_CLIENT_NAME_LEN = 40
class Client
{
// Data members
SOCKET scktClientSock;
char* szClientName;
bool bIsAdmin;
int nNameLength;
public:
// Access methods
void setClientSocket(SOCKET scktClientSock);
SOCKET getClientSocket();
void setClientName(char* szClientName);
char* getClientName();
void setIsAdmin(bool bIsAdmin);
bool getIsAdmin();
int getNameLength();
// Other methods
};
#endif
////////////////////////////////////////////////////
// Client.h
#include "Client.h"
/*
* [Description]: This method changes the SOCKET data member of the Client class
* [Paramaters]:
* _scktClientSock - the new socket client that is being set
* [Return Value]: none
*/
void Client::setClientSocket(SOCKET _scktClientSock)
{
this->scktClientSock = _scktClientSock;
}
/*
* [Description]: This method retrieves the client's socket
* [Paramaters]: none
* [Return Value]: The socket client
*/
SOCKET Client::getClientSocket()
{
return (this->scktClientSock);
}
/*
* [Description]: This method changes the client's name
* [Paramaters]:
* _szClientName - a zero terminated string that describes the new client's name
* [Return Value]: none
*/
void Client::setClientName(char* _szClientName)
{
// Variable definition
int nIndex = -1;
// Code section
this->szClientName = new char[41];
// Copy string char per char
do
{
++nIndex;
this->szClientName[nIndex] = _szClientName[nIndex];
} while (_szClientName[nIndex] != '\0');
// Name length is equal to index
this->nNameLength = nIndex;
}
/*
* [Description]: This method returns a pointer to the first char of the zero terminated client string
* [Paramaters]: none
* [Return Value]: a pointer to the string
*/
char* Client::getClientName()
{
return (this->szClientName);
}
/*
* [Description]: This method is used to set whether the client is an admin or not
* [Paramaters]:
* _bIsAdmin - a boolean indication of whether the user is an admin or not
* [Return Value]: none
*/
void Client::setIsAdmin(bool _bIsAdmin)
{
this->bIsAdmin = _bIsAdmin;
}
/*
* [Description]: This method determines whether the user is an admin or not
* [Paramaters]: none
* [Return Value]: A boolean indication of whether the user is an admin or not
*/
bool Client::getIsAdmin()
{
return (this->bIsAdmin);
}
/*
* [Description]: This method retrieves the client's name length
* [Paramaters]: none
* [Return Value]: the name length
*/
int Client::getNameLength()
{
return (this->nNameLength);
}
Again this is some really old code I've wrote I apologize if it's not so good but It definitely works... also notice that I've contains many different models within the server code, each are seperated by the following
////////////////////////////////////////////////////

Related

How to send double values over TCP/IP in Simulink Support Package for Raspberry Pi

Is it possible to send double values using the TCP/IP client block in the Simulink Support Package for Raspberry Pi?
I have been stuck for a while trying to get this to work:
but using printf("%f %f %f", *((double *)tcp_buffer)), *((double *)tcp_buffer + 1)), *((double *)tcp_buffer + 2))) only prints zeros.
This, however, works ok (printing an int):
After trying to get this working for quite a while, I am under the impression that it will not work (or there is a rather obscured way of doing it). I wound up implementing my own TCP/IP client device driver (i.e. a Simulink block similar to the ones provided by the package) to do the trick and thought I'd leave my implementation here for anyone that's looking. (I think it's better that way anyway as you can really define how you want your client to work.)
To create the device driver, one would need to follow the instructions found on the MATHWORKS site here.
My C implementation for the client is as follows:
/* File: client.h */
#ifndef _CLIENT_H_
#define _CLIENT_H_
#include "rtwtypes.h"
extern int socket_desc;
void init_socket_comm(void);
void send_socket_data(void);
void close_socket(void);
#endif /* _CLIENT_H */
and
/* File: client.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include "client.h"
int socket_desc;
int_T init_socket_comm(void)
{
struct sockaddr_in server; /* Server socket parameters */
/* Create socket and get socket descriptor */
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if (socket_desc < 0)
{
fprintf(stderr, "Could not create socket\n");
exit(EXIT_FAILURE);
}
/* Specify parameters for server socket */
server.sin_addr.s_addr = inet_addr("127.0.0.1"); /* Server TCP IP;
server.sin_family = AF_INET;
server.sin_port = htons(25000); /* TCP port */;
/* Connect socket to server */
if (connect(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0)
{
fprintf(stderr, "Could not connect to server\n");
/* Close socket */
close(socket_desc);
printf("Socket closed successfully.\n");
exit(EXIT_FAILURE);
}
return socket_desc;
}
/* Sends an array of doubles. */
void send_socket_data(void)
{
int buffer_size = 56;
real_T buffer[7] = {3.21232, 5.31453, 10.34108, 7.34652, 2.34524, 4.44432, 3.45642};
unsigned char *buffer_ptr = (unsigned char *)buffer;
int sent_size;
/* Send data to server */
while (buffer_size > 0)
{
if ((sent_size = send(socket_desc, buffer, buffer_size, 0)) < 0)
{
fprintf(stderr, "Send failed.\n");
/* Close socket */
close(socket_desc);
printf("Socket closed successfully.\n");
exit(EXIT_FAILURE);
}
buffer_ptr += sent_size;
buffer_size -= sent_size;
}
}
void close_socket(void)
{
/* Close socket */
close(socket_desc);
}
Next, you'd need you System Object (I named mine TcpClient):
% File: TcpClient.m
classdef TcpClient < matlab.System & coder.ExternalDependency
%
% System object TcpClient block.
properties
% Public, tunable properties.
end
properties (Nontunable)
% Public, non-tunable properties.
end
properties (Access = private)
% Pre-computed constants.
end
methods
% Constructor
function obj = TcpClient(varargin)
% Support name-value pair arguments when constructing the object.
setProperties(obj,nargin,varargin{:});
end
end
methods (Access=protected)
function setupImpl(obj) %#ok<MANU>
if isempty(coder.target)
% Place simulation setup code here
else
% Call C-function implementing device initialization
coder.cinclude('client.h');
coder.ceval('init_socket_comm');
end
end
function stepImpl(obj,u) %#ok<INUSD>
if isempty(coder.target)
% Place simulation output code here
else
% Call C-function implementing device output
coder.ceval('send_socket_data');
end
end
function releaseImpl(obj) %#ok<MANU>
if isempty(coder.target)
% Place simulation termination code here
else
% Call C-function implementing device termination
coder.ceval('close_socket');
end
end
end
methods (Access=protected)
%% Define input properties
function num = getNumInputsImpl(~)
num = 1;
end
function num = getNumOutputsImpl(~)
num = 0;
end
function flag = isInputSizeMutableImpl(~,~)
flag = false;
end
function flag = isInputComplexityMutableImpl(~,~)
flag = false;
end
function validateInputsImpl(~, u)
if isempty(coder.target)
% Run input validation only in Simulation
validateattributes(u,{'double'},{'scalar'},'','u');
end
end
function icon = getIconImpl(~)
% Define a string as the icon for the System block in Simulink.
icon = 'Sink';
end
end
methods (Static, Access=protected)
function simMode = getSimulateUsingImpl(~)
simMode = 'Interpreted execution';
end
function isVisible = showSimulateUsingImpl
isVisible = false;
end
end
methods (Static)
function name = getDescriptiveName()
name = 'Sink';
end
function b = isSupportedContext(context)
b = context.isCodeGenTarget('rtw');
end
function updateBuildInfo(buildInfo, context)
if context.isCodeGenTarget('rtw')
% Update buildInfo
srcDir = fullfile(fileparts(mfilename('fullpath')),'src'); %#ok<NASGU>
includeDir = fullfile(fileparts(mfilename('fullpath')),'include');
addIncludePaths(buildInfo,includeDir);
% Use the following API's to add include files, sources and
addSourceFiles(buildInfo,'client.c', srcDir);
end
end
end
end
Now you can send doubles and if you create your server correctly using the code from here which I adapted to create a function that reads the TCP buffer:
/* File: server.c */
int read_socket_data(int new_socket, void *buffer, int buffer_size)
{
int read_size;
int read_attempts;
/* Continously read TCP buffer */
while ((read_size = recv(new_socket, buffer, buffer_size, 0)) >= 0)
{
if (read_size > 0)
{
/* Print read buffer */
for (int offset = 0; offset < 7; offset++)
{
printf("%lf\n", *((double *)buffer + offset));
}
}
}
return read_size;
}
you can read and print the doubles correctly.

Socket address showing 0.0.0.0, causing failure to send message

I've been working from Beejs Network examples, introducing a few customizations. In particular, I'm trying to use a single structure to store the necessary information related to communications/sockets. I think I'm having trouble populating an addrinfo structure and using it with sendto for a UDP socket. Bellow is my code, which compiles fine, but it fails with the message outlined below
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// Definitions
#define COM_MSG_SIZE 1024
#define COM_HOST_SIZE 128
struct com_socket
{
char *type;
int descriptor;
struct addrinfo addr;
};
void COM_error(char *msg) {
perror(msg);
exit(0);
}
int main()
{
int status;
struct com_socket COM_client;
char addr_str[COM_HOST_SIZE];
// ---------------------------------------------
// Initialize socket
COM_client.type = "UDP";
char *hostname = "192.168.0.110";
char *port_num = "4000";
printf("Creating socket...");
if(strcmp(COM_client.type, "UDP") == 0)
{
COM_client.descriptor = socket(AF_INET, SOCK_DGRAM, 0);
}
// Error check
if(COM_client.descriptor < 0)
{
COM_error(" ERROR opening socket");
}
printf(" Success\n");
//------------------------------------------------------------------------------------------
// Define hints
struct addrinfo hints;
hints.ai_family = AF_INET; // AF_UNSPEC "unspecified" or can use IPv6 = AF_INET6, IPv4 = AF_INET
hints.ai_socktype = SOCK_DGRAM; // Socket type: SOCK_STREAM or SOCK_DGRAM or 0 = auto
hints.ai_flags = AI_CANONNAME;
hints.ai_protocol = 0; // 0 = auto
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_addrlen = 0;
hints.ai_next = NULL;
// Get the linked list of address info
struct addrinfo *host_list;
printf("Building host address list...");
status = getaddrinfo(hostname,port_num,&hints,&host_list);
// returns 0 if succeeds
if (status != 0)
{
COM_error(" ERROR getaddrinfo: %s\n");
}
printf(" Success\n");
//------------------------------------------------------------------------------------------
// Select address
int count = 1;
struct addrinfo *entry;
// Loop through each entry in the "linked list" and pull the necessary one
for (entry = host_list; entry != NULL; entry = entry->ai_next)
{
// Print the list of potential IP addresses
if( NULL == inet_ntop( AF_INET, &((struct sockaddr_in *) entry->ai_addr)->sin_addr, addr_str, sizeof(addr_str) ) )
{
COM_error(" ERROR with inet_ntop\n");
}
printf(" Address entry %d: %s",count,addr_str);
// Update counter
count = count + 1;
// Choose which one to copy
if(strncmp(addr_str,"192.",(size_t) 4) == 0)
{
//memcpy(COM_client.addr,entry, sizeof(struct addrinfo));
COM_client.addr = *entry;
// COM_client.addr.ai_addr = entry->ai_addr;
// COM_client.addr.ai_addrlen = entry->ai_addrlen;
// COM_client.addr.ai_canonname = entry->ai_canonname;
// COM_client.addr.ai_family = entry->ai_family;
// COM_client.addr.ai_flags = entry->ai_flags;
// COM_client.addr.ai_protocol = entry->ai_protocol;
// COM_client.addr.ai_socktype = entry->ai_socktype;
if( inet_ntop( AF_INET, &((struct sockaddr_in *) COM_client.addr.ai_addr)->sin_addr, addr_str, sizeof(addr_str) ) == NULL )
{
COM_error(" ERROR with arguments to inet_ntop\n");
}
printf(" <--------- selected* (%s) \n",addr_str);
break;
}
else
{
printf("\n");
}
}
// Clean
freeaddrinfo(host_list);
//-------------------------------------------------------
char *buffer;
char msg[COM_MSG_SIZE];
strncpy(msg,"BEGIN",COM_MSG_SIZE);
printf("ENTER `COM_msg_send` address length %d\n",COM_client.addr.ai_addrlen);
buffer = calloc(COM_MSG_SIZE+1, sizeof(char));
printf("AFTER calloc `COM_msg_send` address length %d\n",COM_client.addr.ai_addrlen);
// Check to see if we were successful
if (buffer == NULL)
{
printf("ERROR Could not allocate required memory\n");
exit(1);
}
// Copy message to buffer
strncpy(buffer,msg,COM_MSG_SIZE);
printf("Message input: %s Message to be sent: %s\n",msg,buffer);
if( inet_ntop( AF_INET, &((struct sockaddr_in *) COM_client.addr.ai_addr)->sin_addr, addr_str, sizeof(addr_str) ) == NULL )
{
COM_error(" ERROR with arguments to inet_ntop\n");
}
printf("SEND to address (%s) \n",addr_str);
// Send the buffer to the destination address
if(strcmp(COM_client.type, "UDP") == 0)
{
status = sendto(COM_client.descriptor, buffer, strlen(buffer), 0, COM_client.addr.ai_addr, COM_client.addr.ai_addrlen);
// Error check
if (status < 0)
{
COM_error("ERROR could not send message");
}
}
// Free buffer memory
free(buffer);
//---------------------------------------------------------
close(COM_client.descriptor);
return 0;
}
Here is the output showing messages from the print statements as well as the failure
Creating socket... Success
Building host address list... Success
Address entry 1: 192.168.0.110 <--------- selected* (192.168.0.110)
ENTER `COM_msg_send` address length 16
AFTER calloc `COM_msg_send` address length 16
Message input: BEGIN Message to be sent: BEGIN
L1 = 16 L2 = 16
SEND to address (0.0.0.0)
ERROR could not send message: Invalid argument
Showing SEND to address (0.0.0.0), it appears that something is wrong with the address stored in the structure COM_client. Specifically, I believe I'm having trouble with this part
//memcpy(COM_client.addr,entry, sizeof(struct addrinfo));
COM_client.addr = *entry;
// COM_client.addr.ai_addr = entry->ai_addr;
// COM_client.addr.ai_addrlen = entry->ai_addrlen;
// COM_client.addr.ai_canonname = entry->ai_canonname;
// COM_client.addr.ai_family = entry->ai_family;
// COM_client.addr.ai_flags = entry->ai_flags;
// COM_client.addr.ai_protocol = entry->ai_protocol;
// COM_client.addr.ai_socktype = entry->ai_socktype;
As you can see, I've tried various things, all of which fail. I want to continue to use the COM_client structure approach as my intention is to make the code more modular in which I can pass the structure containing all the necessary communication information.
This line
COM_client.addr = *entry;
"tries" to copy a struct addrinfo, which it in fact does, but as it contains pointers and "only" copies the pointers' values. The memory those pointers point to had been allocated by getaddrinfo() and thus will be deallocates by the call to freeaddrinfo() leaving the pointers inside the copy dangle afterwards.
To get around this you need to perform a "deep copy" of a struct addrinfo.
This for example can be done like so:
/* Does a deep copy to where pdst point from where pscr points to.
Returns 0 on success and -1 on error. Sets errno. */
int addrinfo_copy(struct addrinfo * pdst, struct addrinfo * psrc)
{
int result = 0; /* Be optimistic. */
assert(pdst);
assert(psrc);
*pdst = *pscr; /* Copy all. Note that the pointer elements copied
need to be recreated. See below ... */
do
{
pdst->ai_addr = malloc(psrc->ai_addrlen);
if (!pdst->ai_addr)
{
result = -1;
break;
}
memcpy(pdst->ai_addr, psrc->ai_addr, psrc->ai_addrlen);
pdst->ai_canonname = strdup(psrc->ai_canonname); /* Assumes POSIX. */
if (!pdst->ai_canonname)
{
result = -1;
break;
}
} while (0);
return result;
}
To get rid of such a copy you need something like this:
/* Deallocates and sets to a 0/NULL what had been created by
addrinfo_copy(). */
void addrinfo_free(struct addrinfo * p)
{
assert(p);
free(p->ai_addr);
free(p->canonname);
memset(p, 0, sizeof *p); /* In fact not necessary. */
}
Use it like this:
struct addrinfo * entry, * entry_copy;
/* Set entry to something returned by getaddrinfo (). */
...
if (-1 = addrinfo_copy(entry_copy, entry))
{
perror("addrinfo_copy() failed"):
exit(EXIT_FAILURE);
}
/* Deallocate all results returned by getaddrinfo(). */
freeaddrinfo(...);
/* Still use entry_copy here. */
...
/* Clean up. */
addrinfo_free(entry_copy);
As a final note:
If when doing C you observe obscure sudden/unexpected changes in memory content this all most ever dues to having messed up memory management by writing and/or reading to "wrong" memory. This some times happened way long before those changes in memory become obvious and/or in code (seemingly) completely unrelated to where you observe such changes in memory.

Reading from named pipe freezes when piping tshark output

I'm trying to implement a web prefetching system. The purpose of a system like this is to “predict” future requests and prefetch them.
The system builds a predictive model from web navigation logs (Squid access.log files). The model is a dependency graph, where a node representing URL A has an arc to a node representing URL B if URL B has been requested immediately after URL A.
Once the model is built, the system receives queries of URLs requested by users, and make “predictions” based on the graph. Predictions are resources (URLs) very likely to be requested in the future. So, based on predictions, the system prefetches these resources to store them in cache prior to users' requests.
I'm using the following testing scenario:
A process simulate multiple clients, requesting URLs in a file using libcurl. The process runs in a different PC from the prefetching system. PCs are connected directly via an ethernet cable
Requests made by the client simulator are always the same URLs in the same relative time from the first request made. All requests are going to port 3128 (Prefetch PC Squid listen port) (port 80 DNAT to port 3128 in the client).
The prefetching system runs in a CentOS 6.3 box, kernel 2.6.32-71.el6.i686, 2 core Intel Pentium 4 3.00GHz processor, 4 GB RAM.
The prefetching system is one process with multiple threads. The main thread creates the predictive model and generates predictions based on queries. A “listener” thread reads URLs requested by users and prefetches predicted URLs using libcurl. “Listening” means reading from a named pipe (called url_fifo) URLs captured live on an interface using tshark:
stdbuf -o0 tshark -i eth1 tcp port 3128 and "tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420" -T fields -e http.request.full_uri >> url_fifo
Each 10 minutes (1 cycle) the model is updated based on requests from the last cycle. The client tells the system when a cycle ends and so the model is updated. Once the model is updated, the system tells the client to start requesting URLs from the next cycle.
Here is the situation: Sometimes reading from the named pipe freezes. No URLs are read from the pipe even though tshark keeps capturing URLs and redirecting them to the named pipe. After an hour (or a couple of hours) all “buffered” URLs are read in less than 10 minutes. After that, reading from the pipe keeps going ok again. This situation doesn't happen always (50% of times freezes, 50% no).
It seems that there is a buffering issue, since tshark keeps capturing URLs and all requests are correctly logged in Squid's access.log.
In the beginning, I ran tshark with the -l option, so that its output becomes line buffered. Then I started using stdbuf -o0 (no buffering). Anyway the situation still happens.
In the system code, I also tried opening and reading the named pipe as a stream (FILE *) and set the stream as no buffered or line buffered (using setvbuf() function). The situation still happened.
In some cycles requests are faster than in other cycles. Anyway, it doesn't seems to be a fast producer slow consumer issue, since in many repetitions of the test all URLs are correctly read and processed without any freezes.
Is there something am I missing related to named pipes and buffering? I'd really appreciate some guidance.
Assume networking (interfaces, routing, iptables, squid) is ok. I've not had any issues related to it.
Code (assume necessary header files are included):
functions.c
#define BUFLEN 512
#define QUEUE_LEN 64
#define THREADS_LEN 2
pthread_mutex_t model_lock;
pthread_cond_t model_cond, listen_cond;
pthread_t queries_thread, listen_thread;
short int model_is_updating, model_can_update, program_shutdown;
/* Program execution statistics */
Status * program_status;
/* Thread pool */
threadpool_t *pool;
/* program execution */
int
run(void)
{
Graph_Adj_List * gr = NULL; /* Graph as an adjacency list */
char ** reports = NULL;
unsigned report_counter = 0;
/* Init program status */
program_status = status_init();
/* Load list of custom web navigation reports to be used to build the initial
* version of the predictive model */
reports = file_load_reports(program_config.reports_file);
if (!reports)
return 0;
/* Init mutex and cond */
pthread_mutex_init(&model_lock, NULL);
pthread_cond_init(&model_cond, NULL);
pthread_cond_init(&listen_cond, NULL);
/* Lock */
pthread_mutex_lock (&model_lock);
/* Start first cycle */
status_start_cycle(program_status);
/* Create initial version of the predictive model */
gr = create_model_from_files(reports, &report_counter, program_config.reports_limit);
if (!gr)
{
/* Unlock */
pthread_mutex_unlock (&model_lock);
return 0;
}
/* Unlock */
pthread_mutex_unlock (&model_lock);
/* Start threads */
if (pthread_create(&queries_thread, NULL, fifo_predictions_threaded, (void *)gr) ||
pthread_create(&listen_thread, NULL, listen_end_of_cycle, NULL))
program_shutdown = 1;
/* main loop */
while(!program_shutdown)
{
/* lock */
pthread_mutex_lock (&model_lock);
/* wait for clients' announcement of the end of requests from current cycle */
while (!model_can_update)
pthread_cond_wait(&model_cond, &model_lock);
/* set updating flag */
model_is_updating = 1;
/* Update predictive model, based on Squid's access.log from (about to finish)
* current cycle */
adj_list_update_access(gr, program_config.access_file);
/* Save statistics related to the current cycle and finish it */
status_finish_cycle(program_status);
/* Check if last custom report has been read */
if (!reports[report_counter])
{
program_shutdown = 1;
pthread_mutex_unlock (&model_lock);
break;
}
/* Start a new cycle */
status_start_cycle(program_status);
/* Read a new custom report and update the predictive model */
update_model(gr, reports[report_counter]);
report_counter++;
/* Updating is done */
model_is_updating = 0;
/* Model can't be updated until client announces the end of the cycle
* that has just started */
model_can_update = 0;
/* Tell client to start sending requests from the new cycle */
if (!signal_start_cycle())
{
program_shutdown = 1;
pthread_mutex_unlock (&model_lock);
break;
}
/* Signal listener thread that a new cycle has begin */
pthread_cond_signal(&listen_cond);
/* Unlock */
pthread_mutex_unlock (&model_lock);
}
/* Finish threads */
pthread_cancel(listen_thread);
pthread_cancel(queries_thread);
pthread_join(listen_thread, NULL);
pthread_join(queries_thread, NULL);
/* Free memory */
adj_list_free_all2(&gr);
file_reports_free_all(&reports);
pthread_cond_destroy(&model_cond);
pthread_cond_destroy(&listen_cond);
pthread_mutex_destroy(&model_lock);
status_free(&program_status);
return 1;
}
void *
fifo_predictions_threaded(void * data)
{
Graph_Adj_List * gr = (Graph_Adj_List *) data;
/* Set thread cancel type */
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
while (!program_shutdown)
{
pthread_mutex_lock(&model_lock);
/* Pause reading from named pipe while the model is being updated */
while(model_is_updating)
pthread_cond_wait(&listen_cond, &model_lock);
pthread_mutex_unlock(&model_lock);
/* Read URLs from named pipe */
fifo_predictions(gr, program_config.fifo);
}
pthread_exit(NULL);
return NULL;
}
int
fifo_predictions(Graph_Adj_List * gr, const u8 * fifo)
{
u8 cad[BUFLEN] = { '\0' };
u8 * ini = NULL, * fin = NULL, * fullurl = NULL;
int i, fifo_descriptor, read_urls = 0, fullurl_len = 0, incomplete_url = 1;
FILE * fifo_file = NULL;
/* Open fifo in blocking mode */
fifo_descriptor = open(CHAR_CAST fifo, O_RDONLY);
/* Open fifo as a stream */
// fifo_file = fopen(fifo, "r");
// if (!fifo_file)
if (fifo_descriptor == -1)
return 0;
/* If fifo is opened as a stream, set it line buffered */
// setlinebuf(fifo_file);
do
{
if ((i = read(fifo_descriptor, cad, BUFLEN - 1)) == -1)
// if ( fgets(cad, BUFLEN-1, fifo_file) == NULL)
ERROR(__FILE__, __FUNCTION__, __LINE__, "Fifo read error");
else
{
// i = strlen(cad);
cad[i] = '\0';
read_urls = 0;
if (i > 0)
{
int j = 0;
for (j = 0, ini = cad, fin = NULL ; cad[j] != '\0'; j++)
{
if (cad[j] == '\n')
{
/* Save URL */
fin = &cad[j];
ini = (*ini == '\n' ? ini + 1 : ini);
/* Check if string is a continuation of the previously read URL */
read_urls = fin - ini;
read_urls = read_urls >= 0 ? read_urls : 0;
/* Save URL in fullurl string */
fullurl = realloc(fullurl, fullurl_len + read_urls + 1);
memcpy(&fullurl[fullurl_len], ini, read_urls);
fullurl[fullurl_len + read_urls] = '\0';
ini = fin;
incomplete_url = fullurl_len = 0;
/* Ask the model for predictions and fetch them */
fetch_url_predictions2(gr, fullurl);
u8_free(&fullurl);
} else
incomplete_url = 1;
}
if (incomplete_url)
{
ini = (*ini == '\n' ? ini + 1 : ini);
read_urls = &cad[j] - ini;
read_urls = read_urls >= 0 ? read_urls : 0;
fullurl = realloc(fullurl, fullurl_len + read_urls);
memcpy(&fullurl[fullurl_len], ini, read_urls);
fullurl_len += read_urls;
}
}
}
} while (i > 0);
close(fifo_descriptor);
// fclose (fifo_file);
return 1;
}
int
fetch_url_predictions2(Graph_Adj_List * gr, u8 * in_url)
{
String * string_url = NULL;
Headnode * head = NULL;
LinkedList * list = NULL;
LinkedListElem * elem = NULL;
/* Use custom string type */
string_url = string_create_no_len(in_url);
if (!string_url)
return 0;
pthread_mutex_lock(&model_lock);
/* Get URL node */
head = adj_list_get_node(gr, string_url);
if (head)
{
/* Get predictions (URLs) as a linked list */
list = adj_list_predictions_to_list(head);
if (!list)
{
string_free_all(&string_url);
return 0;
}
pthread_mutex_unlock(&model_lock);
/* Callback fetches URLs */
list->callback = &curl_callback_void;
if (!pool)
pool = threadpool_create(THREADS_LEN, QUEUE_LEN, 0);
/* Load URLs to be fetched to threadpool's task queue */
for (elem = list->first; elem; elem = elem->next)
{
CallbackArg arg;
arg.data = arg.copy(elem->data);
threadpool_add_copy_arg(pool, list->callback, &arg, 1, sizeof(arg), 0);
}
linked_list_free_all(&list);
}
pthread_mutex_unlock(&model_lock);
string_free_all(&string_url);
return 1;
}
fetch.c
void
curl_callback_void(void * data)
{
CallbackArg * arg = (CallbackArg *) data;
char * url = (char *) arg->data;
fetch_url(url);
}
static size_t
write_data(void *buffer, size_t size, size_t nmemb, void *userp)
{
return size * nmemb;
}
int
fetch_url(char * url)
{
CURL *curl;
CURLcode res;
struct timeval time;
char * time_string = NULL;
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 15);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
gettimeofday(&time, NULL);
time_string = timeval_to_str(&time);
/* Check for errors */
if (res != CURLE_OK)
{
fprintf(stderr, "\ntime %s curl_easy_perform() (url %s) failed: %s\n",
time_string, url, curl_easy_strerror(res));
}
else
{
fprintf(stderr, "\ntime %s curl_easy_perform() (url %s) fetched ok\n",
time_string, url);
}
fflush(stderr);
free (time_string);
curl_easy_cleanup(curl);
}
return 0;
}
network.c
/*
* Code based on Beej's Networking Guide
*/
#define MSG_LEN 5
#define QUEUE_SIZE 5
extern pthread_mutex_t model_lock;
extern pthread_cond_t model_cond;
extern short int model_can_update, program_shutdown;
extern Config program_config;
// get sockaddr, IPv4 or IPv6:
static void *
get_in_addr(struct sockaddr *sa) {
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*) sa)->sin_addr);
}
return &(((struct sockaddr_in6*) sa)->sin6_addr);
}
void *
listen_end_of_cycle(void * data)
{
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
int yes = 1;
char s[INET_ADDRSTRLEN], msg[MSG_LEN], *str = NULL;
int rv;
int read_bytes;
struct timeval actual_time;
/* Set thread cancel type */
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, program_config.listen_port, &hints, &servinfo))
!= 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return "error";
}
// loop through all the results and bind to the first we can
for (p = servinfo; p != NULL ; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol))
== -1) {
perror("server: socket");
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int))
== -1) {
perror("setsockopt");
return "error";
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
if (p == NULL ) {
fprintf(stderr, "server: failed to bind\n");
return "error";
}
freeaddrinfo(servinfo); // all done with this structure
if (listen(sockfd, QUEUE_SIZE) == -1) {
perror("listen");
return "error";
}
while (!program_shutdown)
{
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *) &their_addr), s, sizeof s);
if ((read_bytes = recv(new_fd, msg, MSG_LEN - 1, 0)) == -1) {
perror("recv");
continue;
}
close(new_fd);
msg[read_bytes] = '\0';
/* Check received message */
if (strcmp(msg, "DONE")) {
perror("Not valid message");
continue;
}
printf("\ngot \"DONE\" from %s\n", s);
fflush(stdout);
/* Lock */
pthread_mutex_lock(&model_lock);
/* Flag used by main thread to allow model update */
model_can_update = 1;
/* Signal model can be updated */
pthread_cond_signal(&model_cond);
/* Unlock */
pthread_mutex_unlock(&model_lock);
}
close(sockfd);
pthread_exit(NULL);
return "ok";
}
int signal_start_cycle(void) {
int sockfd;
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN], *str = NULL;
struct timeval actual_time, aux_time;
struct timeval connect_timeout = { 15, 0 }, max_connect_time = { 0, 0 };
short int connected = 0;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(program_config.client_ip, program_config.client_port,
&hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 0;
}
gettimeofday(&aux_time, NULL);
timeval_add(aux_time, connect_timeout, &max_connect_time);
/* Try several times to connect to the remote side */
do {
// loop through all the results and connect to the first we can
for (p = servinfo; p != NULL ; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol))
== -1) {
perror("client: socket");
continue;
}
gettimeofday(&actual_time, NULL )
printf("\ntrying to connect %s\n", program_config.client_ip);
fflush(stdout);
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("client: connect");
continue;
}
connected = 1;
break;
}
} while (!connected && !timeval_greater_than(actual_time, max_connect_time));
if (p == NULL ) {
fprintf(stderr, "client: failed to connect\n");
return 0;
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *) p->ai_addr), s,
sizeof s);
printf("\nMAIN THREAD: connecting to %s\n", s);
fflush(stdout);
freeaddrinfo(servinfo); // all done with this structure
if (send(sockfd, "DONE", 4, 0) == -1)
{
perror("send");
return 0;
}
printf("\nsent \"DONE\" to %s\n", s);
fflush(stdout);
close(sockfd);
return 1;
}

'Sendto failed'; Error when using sendto-function, using a UDP-socket in C

I have a program which is FEC-encoding data, sending the data; receiving the data at another socket, and decoding the data.
I get an error when the sendto-function is executed in the code attached below. More information about the sendto-function here: Link
The return code of the error is '-1'.
What is the cause of this error and what should I change in the code in order to resolve it?
Print-outs from the 'receiver':
*** Sender -- socket created
***we have a client, and will sent message to server_addr ...server.. will receive messages.. sss
*** Created server socket good. Server socket is 4
***We have a server socket; and now we will try to bind it with the IP_ADDR-local host -- that we sent..
port nr 4783 & ip 127.0.0.1***Bind succeed..
Thread 1
Some lines of eperftool.h
#define PORT_NUM 4783 // Arbitrary port number for the server
#define IP_ADDR "127.0.0.1" // IP address of server1 (*** HARDWIRED ***)
#define SYMBOL_SIZE 1024 //todo..on a different position also
#define MAX_K 1000
#define MAX_N 1500
Code of sender.c:
/* $Id: sender.c 3 2011-03-03 10:48:54Z detchart $ */
/*
* OpenFEC.org AL-FEC Library.
* (c) Copyright 2009-2011 INRIA - All rights reserved
* Contact: vincent.roca#inria.fr
*
* This software is governed by the CeCILL-C license under French law and
* abiding by the rules of distribution of free software. You can use,
* modify and/ or redistribute the software under the terms of the CeCILL-C
* license as circulated by CEA, CNRS and INRIA at the following URL
* "http://www.cecill.info".
*
* As a counterpart to the access to the source code and rights to copy,
* modify and redistribute granted by the license, users are provided only
* with a limited warranty and the software's author, the holder of the
* economic rights, and the successive licensors have only limited
* liability.
*
* In this respect, the user's attention is drawn to the risks associated
* with loading, using, modifying and/or developing or reproducing the
* software by the user in light of its specific status of free software,
* that may mean that it is complicated to manipulate, and that also
* therefore means that it is reserved for developers and experienced
* professionals having in-depth computer knowledge. Users are therefore
* encouraged to load and test the software's suitability as regards their
* requirements in conditions enabling the security of their systems and/or
* data to be ensured and, more generally, to use and operate it in the
* same conditions as regards security.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
/* AL-FEC extended performance evaluation tool */
#include "eperftool.h"
/*
* local variables
*/
static void **encoding_symbols_tab; /* temporary symbol array needed by the FEC encoder */
of_status_t
init_sender (void)
{
of_session_t *ses; /* pointer to a codec instance */
block_cb_t *blk; /* temporary pointer within the blk_cb_tab[] */
UINT32 sbn; /* block sequence number */
UINT32 k; /* k parameter for a given block. Warning, the last block might be shorter */
UINT32 n; /* n parameter for a given block. Warning, the last block might be shorter */
UINT32 esi; /* Encoding Symbol ID */
UINT32 src_idx; /* index for a source symbol in the orig_symb[] table */
UINT32 rep_idx; /* index for a repair symbol in the orig_symb[] table */
symbol_cb_t *src_symb_cb; /* pointer to a source symbol in the orig_symb[] table */
symbol_cb_t *rep_symb_cb; /* pointer to a repair symbol in the orig_symb[] table */
UINT32 tmp_max_k; /* temporary value for max_k */
UINT32 max_n_4_any_blk;/* maximum n value for any block */
#ifdef WIN32
QueryPerformanceCounter(&tv0);
OF_PRINT(("init_start=%lI64f\n", (double)tv0.QuadPart/(double)freq.QuadPart))
#else
gettimeofday(&tv0, NULL);
OF_PRINT(("init_start=%ld.%ld\n", tv0.tv_sec, tv0.tv_usec))
#endif
/*
* determine the blocking structure, which requires to create a temporary FEC session.
*/
if (of_create_codec_instance(&ses, codec_id, OF_ENCODER, of_verbosity) != OF_STATUS_OK) {
OF_PRINT_ERROR(("init_sender: ERROR: of_create_codec_instance() failed\n"))
goto error;
}
if (codec_id == OF_CODEC_REED_SOLOMON_GF_2_M_STABLE) {
if (of_set_control_parameter(ses, OF_RS_CTRL_SET_FIELD_SIZE, (void*)&rs_m_param, sizeof(rs_m_param)) != OF_STATUS_OK) {
OF_PRINT_ERROR(("init_sender: ERROR: of_set_control_parameter() failed\n"))
goto error;
}
}
if (of_get_control_parameter(ses, OF_CTRL_GET_MAX_K, (void*)&max_k, sizeof(max_k)) != OF_STATUS_OK) {
OF_PRINT_ERROR(("init_sender: ERROR: of_get_control_parameter() failed\n"))
goto error;
}
if (of_get_control_parameter(ses, OF_CTRL_GET_MAX_N, (void*)&max_n, sizeof(max_n)) != OF_STATUS_OK) {
OF_PRINT_ERROR(("init_sender: ERROR: of_get_control_parameter() failed\n"))
goto error;
}
if (of_release_codec_instance(ses) != OF_STATUS_OK) {
OF_PRINT_ERROR(("init_sender: ERROR: of_release_codec_instance() failed\n"))
goto error;
}
/*
* determine the practical maximum k and n parameters, taking into
* account the code/codec limitations and the desired code_rate.
* The idea is to have max_k maximum, given max_n and code_rate, for
* optimal erasure recovery performances.
*/
tmp_max_k = (UINT32)floor((double)max_n * code_rate);
max_k = min(tmp_max_k, max_k);
max_n = min((UINT32)((double)max_k / code_rate), max_n);
/* we can now compute the required blocking structure */
of_compute_blocking_struct(max_k, object_size, symbol_size, &bs);
tot_nb_blocks = bs.nb_blocks;
/*
* adjust tot_nb_encoding_symbols and tot_nb_encoding_symbols variables, now we know
* the exact blocking structure.
*/
tot_nb_encoding_symbols = (bs.I * (int)floor((double)(bs.A_large) / code_rate)) +
((bs.nb_blocks - bs.I) * (int)floor((double)(bs.A_small) / code_rate));
ASSERT(tot_nb_encoding_symbols <= tot_nb_source_symbols + tot_nb_repair_symbols);
tot_nb_repair_symbols = tot_nb_encoding_symbols - tot_nb_source_symbols;
OF_PRINT_LVL(1, ("Blocking_struct:\n\ttot_nb_source_symbols=%d, tot_nb_repair_symbols=%d, tot_nb_encoding_symbols=%d, code_rate=%.3f\n\tI=%d, tot_nb_blocks=%d, A_large=%d, A_small=%d\n",
tot_nb_source_symbols, tot_nb_repair_symbols, tot_nb_encoding_symbols, code_rate,
bs.I, tot_nb_blocks, bs.A_large, bs.A_small))
/*
* allocate and inix#tialize the original source and repair symbol buffers.
*/
if ((orig_symb = (char**)calloc(tot_nb_encoding_symbols, sizeof(char*))) == NULL) {
OF_PRINT_ERROR(("init_sender: ERROR: out of memory\n"))
goto no_mem;
}
/* source symbol buffers first... */
for (src_idx = 0; src_idx < tot_nb_source_symbols; src_idx++) {
char *symb;
UINT32 i;
/*
* buffer is 0'ed... Leave it like that, except for the first
* four bytes where we copy the pkt seq number.
*/
if ((symb = (char*)calloc(1, symbol_size)) == NULL) {
OF_PRINT_ERROR(("init_sender: ERROR: out of memory\n"))
goto no_mem;
}
orig_symb[src_idx] = symb;
/* fill each source symbol with some random content, except the first
* word which is equal to the symbol ID. This is useful to test the symbol
* integrity after decoding */
for (i = 0; i < symbol_size; i++) {
symb[i] = (char)rand();
}
*(UINT32 *)symb = (UINT32)src_idx;
//symb[src_idx%symbol_size]=1;
//of_print_composition(symb, symbol_size);
}
/* ... and then repair symbol buffers */
for (rep_idx = tot_nb_source_symbols; rep_idx < tot_nb_encoding_symbols; rep_idx++) {
orig_symb[rep_idx] = (char*)calloc(1, symbol_size);
if (orig_symb[rep_idx] == NULL) {
OF_PRINT_ERROR(("init_sender: ERROR: out of memory\n"))
goto no_mem;
}
/* repair symbols will be initialized later... */
}
/*
* now allocate the block and symbol control structures.
*/
if (!(blk_cb_tab = (block_cb_t*)calloc(tot_nb_blocks, sizeof(block_cb_t)))) {
OF_PRINT_ERROR(("init_sender: ERROR: out of memory\n"))
goto no_mem;
}
if (!(symb_cb_tab = (symbol_cb_t*)calloc(tot_nb_encoding_symbols, sizeof(symbol_cb_t)))) {
OF_PRINT_ERROR(("init_sender: ERROR: out of memory\n"))
goto no_mem;
}
/* ...and initialize the various block/symbol control structures */
src_idx = 0;
src_symb_cb = symb_cb_tab;
rep_idx = tot_nb_source_symbols;
rep_symb_cb = &(symb_cb_tab[tot_nb_source_symbols]);
max_n_4_any_blk = 0;
for (sbn = 0, blk = blk_cb_tab; sbn < tot_nb_blocks; sbn++, blk++) {
if (sbn < (UINT32)bs.I) {
k = bs.A_large;
} else {
k = bs.A_small;
}
n = (UINT32)floor((double)k / code_rate);
max_n_4_any_blk = (n < max_n_4_any_blk) ? max_n_4_any_blk : n;
/* init block control block */
blk->sbn = sbn;
blk->k = k;
blk->n = n;
blk->first_src_symbol_idx = src_idx;
blk->first_repair_symbol_idx = rep_idx;
blk->is_decoded = false;
blk->nb_symbols_received = 0;
OF_TRACE_LVL(1, ("init_sender: block: sbn=%d, k=%d, n=%d, first_src_symbol_idx=%d, 1st_rep_symbol_idx=%d\n",
sbn, blk->k, blk->n,
blk->first_src_symbol_idx, blk->first_repair_symbol_idx))
/* init source symbols control block */
for (esi = 0; esi < k; esi++, src_symb_cb++, src_idx++) {
src_symb_cb->esi = esi;
src_symb_cb->sbn = sbn;
}
/* and init repair symbols control block */
for (esi = k; esi < n; esi++, rep_symb_cb++, rep_idx++) {
rep_symb_cb->esi = esi;
rep_symb_cb->sbn = sbn;
}
}
/*
* allocate the table containing the various symbols of a block. This table
* is allocated once and reused by all blocks of the object, with pointers to
* different symbols of course, for encoding purposes.
*/
if (!(encoding_symbols_tab = (void**)calloc(max_n_4_any_blk, sizeof(void*)))) {
OF_PRINT_ERROR(("init_sender: ERROR: out of memory\n"))
goto no_mem;
}
#ifdef WIN32
QueryPerformanceCounter(&tv1);
OF_PRINT(("init_end=%I64f init_time=%I64f\n",
(double)tv1.QuadPart / (double)freq.QuadPart,
(double)(tv1.QuadPart-tv0.QuadPart) / (double)freq.QuadPart ))
#else
gettimeofday(&tv1, NULL);
timersub(&tv1, &tv0, &tv_delta);
OF_PRINT(("init_end=%ld.%ld init_time=%ld.%06ld\n",
tv1.tv_sec, tv1.tv_usec, tv_delta.tv_sec, tv_delta.tv_usec))
#endif
//INIT SENDER SOCKET
// >>> Step #1 <<<
// Create a socket
// - AF_INET is Address Family Internet and SOCK_DGRAM is datagram
client_s = socket(AF_INET, SOCK_DGRAM, 0);
if (client_s < 0)
{
printf("*** ERROR - socket() failed \n");
exit(-1);
}
printf("*** Sender -- socket created \n");
// >>> Step #2 <<<
// Fill-in server1 socket's address information
server_addr.sin_family = AF_INET; // Address family to use
server_addr.sin_port = htons(PORT_NUM); // Port num to use
server_addr.sin_addr.s_addr = inet_addr(IP_ADDR); // IP address to use
printf("***we have a client, and will sent message to server_addr ...server.. will receive messages.. sss\n");
return OF_STATUS_OK;
no_mem:
error:
return OF_STATUS_ERROR;
}
of_status_t
encode (void)
{
of_session_t *ses; /* pointer to a codec instance */
block_cb_t *blk; /* temporary pointer within the blk_cb_tab[] */
UINT32 sbn; /* block sequence number */
UINT32 k; /* k parameter for a given block. Warning, the last block might be shorter */
UINT32 n; /* n parameter for a given block. Warning, the last block might be shorter */
UINT32 esi; /* Encoding Symbol ID */
UINT32 i;
/*
* go through each block of the object, initialize all the structures
* and create repair symbols.
*/
#ifdef WIN32
QueryPerformanceCounter(&tv0);
OF_PRINT(("encoding_start=%lI64f\n", (double)tv0.QuadPart / (double)freq.QuadPart))
#else
gettimeofday(&tv0, NULL);
OF_PRINT(("encoding_start=%ld.%ld\n", tv0.tv_sec, tv0.tv_usec))
#endif
for (sbn = 0, blk = blk_cb_tab; sbn < tot_nb_blocks; sbn++, blk++) {
k = blk->k;
n = blk->n;
/* don't forget to initialize the encoding symbol tab, used by the
* FEC codec during encoding, since we cannot use the orig_symb table
* where the source/repair symbols of a block are not sequential :-( */
for (esi = 0; esi < k; esi++) {
encoding_symbols_tab[esi] = (void*)(orig_symb[blk->first_src_symbol_idx + esi]);
}
for (; esi < n; esi++) {
encoding_symbols_tab[esi] = (void*)(orig_symb[blk->first_repair_symbol_idx + (esi - k)]);
}
/*
* create the codec instance and initialize it accordingly.
* The case of a parity check matrix given in a file is handled
* differently...
*/
#ifdef OF_USE_LDPC_FROM_FILE_CODEC
if (codec_id == OF_CODEC_LDPC_FROM_FILE_ADVANCED)
{
if (of_create_codec_instance(&ses, codec_id, OF_ENCODER, of_verbosity) != OF_STATUS_OK) {
OF_PRINT_ERROR(("ERROR: of_create_codec_instance() failed for codec_id %d\n", codec_id))
goto error;
}
of_ldpc_ff_parameters_t params;
params.encoding_symbol_length = symbol_size;
params.pchk_file = ldpc_matrix_file_name;
if (of_set_fec_parameters(ses, (of_parameters_t*)&params) != OF_STATUS_OK) {
OF_PRINT_ERROR(("ERROR: of_set_fec_parameters() failed for codec_id %d\n", codec_id))
goto error;
}
k = params.nb_source_symbols;
n = params.nb_source_symbols + params.nb_repair_symbols;
} else
#endif
{
ses = create_and_init_codec_instance(codec_id, OF_ENCODER, k, n, blk);
if (ses == NULL) {
OF_PRINT_ERROR(("ERROR: create_and_init_codec_instance() failed for codec_id %d/OF_ENCODER\n", codec_id))
goto error;
}
}
/*
* perform encoding and finally release the FEC codec instance.
*/
for (esi = k; esi < n; esi++) {
if (of_build_repair_symbol(ses, encoding_symbols_tab, esi) != OF_STATUS_OK) {
OF_PRINT_ERROR(("ERROR: of_build_repair_symbol() failed\n"))
goto error;
}
}
//SEND THE PACKETS TO THE RECEIVE!!!
#ifdef WIN
WORD wVersionRequested = MAKEWORD(1,1); // Stuff for WSA functions
WSADATA wsaData; // Stuff for WSA functions
#endif
int server_s; // Server socket descriptor
struct sockaddr_in server_addr; // Server Internet address
struct sockaddr_in client_addr; // Client Internet address..i.e //receiver
struct in_addr client_ip_addr; // Client IP address
int addr_len; // Internet address length
char out_buf[symbol_size]; // Output buffer for data
char in_buf[symbol_size]; // Input buffer for data
int retcode; // Return code
#ifdef WIN
// This stuff initializes winsock
WSAStartup(wVersionRequested, &wsaData);
#endif
// >>> Step #3 <<<
// Now send the message to server. The "+ 1" is for the end-of-string
// delimiter
printf("*** Start sending messages.. \n");
//n is number of symbols to sent -- repair + original..
int j= 0;
for (j=0; j < n ; j++ )
{
//fprintf ("sending test..first char is %c and %c",(char*) ///encoding_symbols_tab[j]);
retcode = sendto(client_s, (const void*) encoding_symbols_tab[j], symbol_size, 0,
(struct sockaddr *)&server_addr, sizeof(server_addr) );
if (retcode < 0)
{
printf("*** ERROR - sendto() failed.. retcode is %d \n", retcode);
exit(-1);
}
else
printf("*** ERROR - sendto() successs \n");
}
Some code of the receiver:
// >>> Step #1 <<<
// Create a socket
// - AF_INET is Address Family Internet and SOCK_DGRAM is datagram
server_s = socket(AF_INET, SOCK_DGRAM, 0);
if (server_s < 0)
{
printf("*** ERROR - socket() failed \n");
exit(-1);
}
else
printf("*** Created server socket good. Server socket is %d \n", server_s);
// >>> Step #2 <<<
// Fill-in my socket's address information
server_addr.sin_family = AF_INET; // Address family to use
server_addr.sin_port = htons(PORT_NUM); // Port number to use
server_addr.sin_addr.s_addr = htonl(IP_ADDR); // Listen on any IP address
printf("***We have a server socket; and now we will try to bind it with the IP_ADDR-local host -- that we sent.. \n port nr %d & ip %s", PORT_NUM, IP_ADDR);
retcode = bind(server_s, (struct sockaddr *)&server_addr,
sizeof(server_addr));
if (retcode < 0)
{
printf("*** ERROR - bind() failed \n");
exit(-1);
}
else
printf("***Bind succeed.. \n");
//Storing all messages in in_buf -- here we will receive one; rest in code in decode-function.
// >>> Step #3 <<<
// Wait to receive a message from client
pthread_t thread1;
int iret1;
char *message1 = "Thread 1";
iret1 = pthread_create( &thread1, NULL, waitToReceiveMessageFromClient, (void*) message1);
#include <stdlib.h>
#include <errno.h>
#include <strings.h>
...
retcode = some_system_call(...);
if (retcode == -1)
{
int err = errno;
fprintf(stderr, "*** ERROR - bind() failed:%d(%s)\n"
, err, strerror(err)
);
exit(EXIT_FAILURE);
}
BTW: there is also perror()

Multicasting via UDP from a different thread

I was trying to create an application that allows me to multicast my webcam feed over my LAN using a specific multicast address and using sendto() to just send the frame buffer. The application I am trying to build is pretty much the same as on this site
http://nashruddin.com/Streaming_OpenCV_Videos_Over_the_Network
and uses the same architecture.
Only instead of a TCP socket I use SOCK_DGRAM. The problem is that when I use the sendto() function from a different thread it tends to fail i.e it returns -1 and errno gets set to 90 (EMSGSIZE), this basically means that the packet formed is too large to be sent over the network.
But this happens even if I try to send a simple string (like "hello") to the same multicast address. This seems to work fine if the application is a single thread one. that is to say i just capture the image and multicast it all in the same thread. This is the code:
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "cv.h"
#include "highgui.h"
#define PORT 12345
#define GROUP "225.0.0.37"
CvCapture* capture;
IplImage* img0;
IplImage* img1;
int is_data_ready = 0;
int serversock, clientsock;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void* streamServer(void* arg);
void quit(char* msg, int retval);
int main(int argc, char** argv)
{
pthread_t thread_s;
int key;
if (argc == 2) {
capture = cvCaptureFromFile(argv[1]);
} else {
capture = cvCaptureFromCAM(0);
}
if (!capture) {
quit("cvCapture failed", 1);
}
img0 = cvQueryFrame(capture);
img1 = cvCreateImage(cvGetSize(img0), IPL_DEPTH_8U, 1);
cvZero(img1);
cvNamedWindow("stream_server", CV_WINDOW_AUTOSIZE);
/* print the width and height of the frame, needed by the client */
fprintf(stdout, "width: %d\nheight: %d\n\n", img0->width, img0->height);
fprintf(stdout, "Press 'q' to quit.\n\n");
/* run the streaming server as a separate thread */
if (pthread_create(&thread_s, NULL, streamServer, NULL)) {
quit("pthread_create failed.", 1);
}
while(key != 'q') {
/* get a frame from camera */
img0 = cvQueryFrame(capture);
if (!img0) break;
img0->origin = 0;
cvFlip(img0, img0, -1);
/**
* convert to grayscale
* note that the grayscaled image is the image to be sent to the client
* so we enclose it with pthread_mutex_lock to make it thread safe
*/
pthread_mutex_lock(&mutex);
cvCvtColor(img0, img1, CV_BGR2GRAY);
is_data_ready = 1;
pthread_mutex_unlock(&mutex);
/* also display the video here on server */
cvShowImage("stream_server", img0);
key = cvWaitKey(30);
}
/* user has pressed 'q', terminate the streaming server */
if (pthread_cancel(thread_s)) {
quit("pthread_cancel failed.", 1);
}
/* free memory */
cvDestroyWindow("stream_server");
quit(NULL, 0);
}
/**
* This is the streaming server, run as a separate thread
* This function waits for a client to connect, and send the grayscaled images
*/
void* streamServer(void* arg)
{
struct sockaddr_in server;
/* make this thread cancellable using pthread_cancel() */
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
/* open socket */
if ((serversock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
quit("socket() failed", 1);
}
memset(&server,0,sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = inet_addr(GROUP);
int opt = 1;
//if(setsockopt(serversock,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(int))==-1){
// quit("setsockopt failed",0);
//}
// /* setup server's IP and port */
// memset(&server, 0, sizeof(server));
// server.sin_family = AF_INET;
// server.sin_port = htons(PORT);
// server.sin_addr.s_addr = INADDR_ANY;
//
// /* bind the socket */
// if (bind(serversock, (const void*)&server, sizeof(server)) == -1) {
// quit("bind() failed", 1);
// }
//
// /* wait for connection */
// if (listen(serversock, 10) == -1) {
// quit("listen() failed.", 1);
// }
//
// /* accept a client */
// if ((clientsock = accept(serversock, NULL, NULL)) == -1) {
// quit("accept() failed", 1);
// }
/* the size of the data to be sent */
int imgsize = img1->imageSize;
int bytes=0, i;
/* start sending images */
while(1)
{
/* send the grayscaled frame, thread safe */
pthread_mutex_lock(&mutex);
if (is_data_ready) {
// bytes = send(clientsock, img1->imageData, imgsize, 0);
is_data_ready = 0;
if((bytes = sendto(serversock,img1->imageData,imgsize,0,(struct sockaddr*)&server,sizeof(server)))==-1){
quit("sendto FAILED",1);
}
}
pthread_mutex_unlock(&mutex);
// /* if something went wrong, restart the connection */
// if (bytes != imgsize) {
// fprintf(stderr, "Connection closed.\n");
// close(clientsock);
//
// if ((clientsock = accept(serversock, NULL, NULL)) == -1) {
// quit("accept() failed", 1);
// }
// }
/* have we terminated yet? */
pthread_testcancel();
/* no, take a rest for a while */
usleep(1000);
}
}
/**
* this function provides a way to exit nicely from the system
*/
void quit(char* msg, int retval)
{
if (retval == 0) {
fprintf(stdout, (msg == NULL ? "" : msg));
fprintf(stdout, "\n");
} else {
fprintf(stderr, (msg == NULL ? "" : msg));
fprintf(stderr, "\n");
}
if (clientsock) close(clientsock);
if (serversock) close(serversock);
if (capture) cvReleaseCapture(&capture);
if (img1) cvReleaseImage(&img1);
pthread_mutex_destroy(&mutex);
exit(retval);
}
In the sendto() call, you reference imgsize which is initialized to img1->imageSize.
But I don't see where img1->imageSize is set and it appears that imgsize is never updated.
So first check that the imgsize value being passed to sendto() is correct.
Then check that it is not too large:
UDP/IP datagrams have a hard payload limit of 65,507 bytes. However, an IPv4 network is not required to support more than 548 bytes of payload. (576 is the minimum IPv4 MTU size, less 28 bytes of UDP/IP overhead). Most networks have an MTU of 1500, giving you a nominal payload of 1472 bytes.
Most networks allow you to exceed the MTU by breaking the datagram into IP fragments, which the receiving OS must reassemble. This is invisible to your application: recvfrom() either gets the whole reassembled packet or it gets nothing. But the odds of getting nothing go up with fragmentation because the loss of any fragment will cause the entire packet to be loss. In addition, some routers and operating systems have obscure security rules which will block some UDP patterns or fragments of certain sizes.
Finally, any given network may enforce a maximum datagram size even with fragmentation, and this is often much less than 65507 bytes.
Since you are dealing with a specific network, you will need to experiment to see how big you can reliably go.
UDP/IP at Wikipedia
IPv4 at Wikipedia
Are you absolutely sure that you don't try to send more than limit of UDP which is around 65500 bytes? From my experience you shouldn't even send more than Ethernet packet limit which is around 1500 bytes to keep best UDP reliability.
I think that right now you are trying to send much more data in a form of stream. UDP isn't a stream protocol and you can't replace TCP by it. But of course it is possible to use UDP to send video stream on multicast, but you need some protocol on top of UDP that will handle message size limit of UDP. In real world RTP protocol on top of UDP is used for such kind of task.

Resources