How can i send and recv multiple files size in one socket c++? - sockets

i'm trying to develop a client/server application to share files..
1- Client send file size
2- Client send file data (name + content)
3- Server recv file size
4- Server recv file data (name + content)
I have my code that is working good for one file, and i'm asking how to edit it so i can send and receive size of multiple files ?
Can anyone help Plz !!!
Client code :
cout << "[Client] Sending files name to the Server... " << endl ;
int i=0;
while(i<files_vector.size()){
/************ Read & Send filename *************/
string filename = files_vector[i].getFullNameFile();
string test = filename+"&&";
size_t nameLen = strlen(test.c_str());
if(filename == "." || filename == "..")
continue;
string path_file = cf.pathSrcFiles+filename;
std::ifstream infile(path_file, std::ifstream::binary);
int32_t sizef = files_vector[i].getTaille();
/*** Send file size to server ***/
char fsize[256];
sprintf(fsize, "%d", nameLen+sizef);
if(send(sock, fsize, sizeof(fsize),0) < 0){
perror("Error sending file size\n");
exit(1);
}
/**** Send file data ****/
char content_file[sizef];
bzero(content_file, sizef);
infile.read(content_file,sizef);
string concat = test+string(content_file);
char file[sizef];
strcpy(file, concat.c_str());
cout << "content : " << file << endl;
cout << "size : " << nameLen+sizef << endl;
if(send(sock, file, nameLen+sizef, 0) < 0)
{
cout << stderr << "ERROR: Failed to send file" << filename << "
(error no = " << errno << ")" << endl;
break;
}
bzero(content_file, sizef);
infile.close();
cout << "Ok File " << filename << " from Client was Sent!\n" << endl;
i++;
}
Server code :
char csize[256];
int rc;
int32_t fsize;
/** Receive file size **/
if(rc = recv(sock, csize, 256, 0)) < 0){
cout << "Error receiving file size" << endl;
exit(1);
}
csize[rc] = '\0';
fsize = atoi(csize);
int n = 0;
int bytes_read = 0;
char* file;
file = new char[fsize];
memset(file, 0, fsize);
/** Receive file data **/
while((n = recv(sock, file+bytes_read, fsize-bytes_read, 0) > 0) &&
(bytes_read < fsize)){
cout << "content : " << file << endl;
bytes_read += n;
memset(file, 0, fsize);
}
delete[] file;

Related

Want some guide about how to use nvjpegEncodeYUV()

I am trying to implement some jpeg encoding cuda code based one a sample code below:
https://docs.nvidia.com/cuda/nvjpeg/index.html#nvjpeg-encode-examples
I post all the code, test result and Makefile and input file.
I am testing with NVIDIA 2080 HW + cuda 11.2
But as you would be able to find from this question, the result is fail. First fail is from nvjpegEncodeYUV() The returned error code is 2. That complains for some invalid parameters. What might be wrong?
#include <iterator>
#include <fstream>
#include <iostream>
#include <vector>
#include <cassert>
#include <unistd.h>
#include "nppdefs.h"
#include "nppi_support_functions.h"
#include "nppi_color_conversion.h"
#include "nvjpeg.h"
#include "cuda_runtime.h"
#define DEFAULT_RAWFILE "./uyvy422.raw"
//file >>> buff_UYVY
int read_raw(const char *file2read, unsigned char *buff_UYVY)
{
if (!file2read) {
std::cout << "file2read empty!!" << std::endl;
return 1;
}
if (!buff_UYVY) {
std::cout << "buff_UYVY empty!!" << std::endl;
return 1;
}
std::string file_uyvy(file2read);
std::ifstream stream_uyvy;
stream_uyvy.open(file_uyvy, std::ios::in | std::ios::binary);
if (!stream_uyvy.is_open())
{
std::cerr << "[ERROR] cannot open the raw file " << file_uyvy
<< std::endl;
std::cerr << std::endl;
assert(0);
}
stream_uyvy.read((char*)buff_UYVY, 1920*1080*2);
stream_uyvy.close();
return 0;
}
int main(int argc, char*argv[])
{
unsigned char *buff_UYVY =
new unsigned char[1920 * 1080 * 2];
//file >>> buff_UYVY
int ret;
if (argv[1]) {
ret = read_raw(argv[1], buff_UYVY);
} else {
ret = read_raw(DEFAULT_RAWFILE, buff_UYVY);
}
if (ret != 0) {
std::cout << "read_raw() failed!!" << std::endl;
return ret;
}
if (!buff_UYVY) {
std::cout << "buff_UYVY empty!!" << std::endl;
return 1;
}
cudaError_t err_cu_api;
Npp8u* gpu_buff_CbYCr422;
err_cu_api = cudaMalloc((void**)&gpu_buff_CbYCr422,
1920*1080*2);
err_cu_api = cudaMemcpy((void*)gpu_buff_CbYCr422,
(const void*)buff_UYVY,
1920*1080*2,
cudaMemcpyHostToDevice);
//////////////////////////////////////////////////////////////////////////////
//https://docs.nvidia.com/cuda/nvjpeg/index.html#nvjpeg-encode-examples
nvjpegStatus_t status;
nvjpegHandle_t nv_handle;
nvjpegEncoderState_t nv_enc_state;
nvjpegEncoderParams_t nv_enc_params;
cudaStream_t stream = 0;
// initialize nvjpeg structures
status = nvjpegCreateSimple(&nv_handle);
std::cout << "nvjpegCreateSimple : " << status << std::endl;
status = nvjpegEncoderStateCreate(nv_handle, &nv_enc_state, stream);
std::cout << "nvjpegEncoderStateCreate : " << status << std::endl;
status = nvjpegEncoderParamsCreate(nv_handle, &nv_enc_params, stream);
std::cout << "nvjpegEncoderParamsCreate : " << status << std::endl;
nvjpegImage_t imgdesc =
{
{
gpu_buff_CbYCr422,
gpu_buff_CbYCr422 + 1920*1080,
gpu_buff_CbYCr422 + 1920*1080*2,
gpu_buff_CbYCr422 + 1920*1080*3
},
{
1920,
1920,
1920,
1920
}
};
// Compress image
status = nvjpegEncodeYUV(nv_handle, nv_enc_state, nv_enc_params,
&imgdesc, NVJPEG_CSS_422, 1920, 1080,
stream);
std::cout << "nvjpegEncodeYUV : " << status << std::endl;
// get compressed stream size
size_t length;
status = nvjpegEncodeRetrieveBitstream(nv_handle, nv_enc_state, NULL,
&length, stream);
std::cout << "nvjpegEncodeRetrieveBitstream : " << status << std::endl;
// get stream itself
cudaStreamSynchronize(stream);
std::vector<char> jpeg(length);
status = nvjpegEncodeRetrieveBitstream(nv_handle, nv_enc_state,
(unsigned char*)jpeg.data(), &length, 0);
std::cout << "nvjpegEncodeRetrieveBitstream : " << status << std::endl;
// write stream to file
cudaStreamSynchronize(stream);
std::ofstream output_file("test.jpg", std::ios::out | std::ios::binary);
output_file.write(jpeg.data(), length);
output_file.close();
//https://docs.nvidia.com/cuda/nvjpeg/index.html#nvjpeg-encode-examples
//////////////////////////////////////////////////////////////////////////////
cudaFree(gpu_buff_CbYCr422);
err_cu_api = err_cu_api;
delete[] buff_UYVY;
return 0;
}
$ ./test
nvjpegCreateSimple : 0
nvjpegEncoderStateCreate : 0
nvjpegEncoderParamsCreate : 0
nvjpegEncodeYUV : 2
nvjpegEncodeRetrieveBitstream : 2
nvjpegEncodeRetrieveBitstream : 2
CC = g++
CFLAGS = -v -Wall -I/usr/local/cuda/include -g
LDFLAGS += -L/usr/local/cuda/lib64
SRCS = main_gpu.cpp
PROG = test
OPENCV = `pkg-config opencv4 --cflags --libs`
LIBS = $(OPENCV) \
-lcudart \
-lnppisu \
-lnpps \
-lnppc \
-lnppial \
-lnppicc \
-lnppidei \
-lnppif \
-lnppig \
-lnppim \
-lnppist \
-lnppitc \
-lnvjpeg
.PHONY: all clean
all: $(PROG)
$(PROG):$(SRCS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $(PROG) $(SRCS) $(LIBS)
clean:
rm -f $(OBJS) $(PROG) *.jpg *.bmp
getting input file:
git clone https://github.com/jumogehn/Jumogehn.git
uyvy422.raw is it.
Based on what I see in your code, I'm guessing your input storage format is ordinary YUV422:
U0 Y0 V0 Y1 U2 Y2 V2 Y3 U4 Y4 V4…
That is an interleaved storage format. However the docs for nvjpegEncodeYUV state:
The source argument should be filled with the corresponding YUV planar data.
So you would need to convert your interleaved input into planar storage of a Y plane followed by a U plane followed by a V plane.
As a result, your imgdesc would need to change, because the pitch of U and V planes is half that of the Y plane:
nvjpegImage_t imgdesc =
{
{
gpu_buff_CbYCr422, // pointer to start of Y plane
gpu_buff_CbYCr422 + 1920*1080, // pointer to start of U plane
gpu_buff_CbYCr422 + 1920*1080 + 960*1080, // pointer to start of V plane
NULL
},
{
1920, // pitch of Y plane
960, // pitch of U plane
960, // pitch of V plane
0
}
};
Finally, it seems you need to set the Sampling Factors in the Params:
$ cat t2017.cpp
#include "nvjpeg.h"
#include "cuda_runtime.h"
#include <iostream>
#define DEFAULT_RAWFILE "./uyvy422.raw"
int main(int argc, char*argv[])
{
unsigned char *buff_UYVY =
new unsigned char[1920 * 1080 * 2];
cudaError_t err_cu_api;
unsigned char* gpu_buff_CbYCr422;
err_cu_api = cudaMalloc((void**)&gpu_buff_CbYCr422,
1920*1080*2);
err_cu_api = cudaMemcpy((void*)gpu_buff_CbYCr422,
(const void*)buff_UYVY,
1920*1080*2,
cudaMemcpyHostToDevice);
//////////////////////////////////////////////////////////////////////////////
//https://docs.nvidia.com/cuda/nvjpeg/index.html#nvjpeg-encode-examples
nvjpegStatus_t status;
nvjpegHandle_t nv_handle;
nvjpegEncoderState_t nv_enc_state;
nvjpegEncoderParams_t nv_enc_params;
cudaStream_t stream = 0;
// initialize nvjpeg structures
status = nvjpegCreateSimple(&nv_handle);
std::cout << "nvjpegCreateSimple : " << status << std::endl;
status = nvjpegEncoderStateCreate(nv_handle, &nv_enc_state, stream);
std::cout << "nvjpegEncoderStateCreate : " << status << std::endl;
status = nvjpegEncoderParamsCreate(nv_handle, &nv_enc_params, stream);
std::cout << "nvjpegEncoderParamsCreate : " << status << std::endl;
nvjpegImage_t imgdesc =
{
{
gpu_buff_CbYCr422,
gpu_buff_CbYCr422 + 1920*1080,
gpu_buff_CbYCr422 + 1920*1080 + 960*1080,
NULL
},
{
1920,
960,
960,
0
}
};
status = nvjpegEncoderParamsSetSamplingFactors(nv_enc_params, NVJPEG_CSS_422, stream);
std::cout << "nvjpegEncoderParamsSetSamplingFactors: " << status << std::endl;
// Compress image
status = nvjpegEncodeYUV(nv_handle, nv_enc_state, nv_enc_params,
&imgdesc, NVJPEG_CSS_422, 1920, 1080,
stream);
std::cout << "nvjpegEncodeYUV : " << status << std::endl;
}
$ g++ t2017.cpp -I/usr/local/cuda/include -L/usr/local/cuda/lib64 -lnvjpeg -lcudart -o t2017
$ ./t2017
nvjpegCreateSimple : 0
nvjpegEncoderStateCreate : 0
nvjpegEncoderParamsCreate : 0
nvjpegEncoderParamsSetSamplingFactors: 0
nvjpegEncodeYUV : 0
$
I'm not suggesting this fixes every possible error in your code, merely that it seems to address this question:
First fail is from nvjpegEncodeYUV() The returned error code is 2. That complains for some invalid parameters. What might be wrong?

Sometimes, the asio::tcp::socket object gets closed automatically before calling shutdown/close

Once in 5 times, I get this "Bad file descriptor"error when I am attempting to shutdown or close the asio::ip::tcp::socket object. The following is the function to close the acceptor and socket.
void close_server()
{
acceptor_instance.close(error_code);
if (error_code)
{
std::cerr << "close_server(): acceptor::close()" << "Error: " << error_code.message() << std::endl;
}
if(socket_instance.is_open())
{
socket_instance.shutdown(asio::ip::tcp::socket::shutdown_both, error_code);
if (error_code)
{
std::cerr << "close_server(): socket::close()" << "Error: " << error_code.message() << std::endl;
}
socket_instance.close(error_code);
if (error_code)
{
std::cerr << "close_server(): socket::close()" << "Error: " << error_code.message() << std::endl;
}
}
else
{
std::cerr << "close_server(): socket_instance is already CLOSED" << std::endl;
}
}
Sometimes the socket_intance.is_open() fails. Attempting to call the socket.shutdown() or socket.close() without checking if the socket is open, gives "Bad file descriptor" error, that means the socket was already closed.
How to identify the cause?
How to know when it was closed?

How fix strange syntax problem when using execute function?

I met an error when trying to use a function called execute to use one database. The information shows me that's about syntax, but I don't think so.
The following is my critical code and important information about the error.
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'u' at line 1
#include <stdlib.h>
#include <iostream>
/*
Include directly the different
headers from cppconn/ and mysql_driver.h + mysql_util.h
(and mysql_connection.h). This will reduce your build time!
*/
#include<string>
#include "mysql_connection.h"
#include <mysql_driver.h>
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
using namespace std;
using namespace sql;
int main()
{
try {
sql::mysql::MySQL_Driver driver;
cout<<" driver "<<endl;
sql::Connection *con = NULL;
cout<<" con"<<endl;
sql::Statement *stmt;
cout<<" stmt"<<endl;
sql::ResultSet *res;
cout<<" res"<<endl;
/* Create a connection */
//driver = sql::mysql::MySQL_Driver::MySQL_Driver();
SQLString ip_port("localhost:3306");
cout<<"some debug string"<<endl;
SQLString user("debian-sys-maint");
SQLString password("fTlykRye1LwttC8f");
con = driver.connect(ip_port, user, password);
assert(con!=NULL);
cout<<" root"<<endl;
/* Connect to the MySQL test database */
SQLString schema("account");
//con->setSchema(schema);
cout<<" table"<<endl;
stmt = con->createStatement();
cout<<" table*2"<<endl;
assert(stmt!=NULL);
SQLString db("use account");
stmt->execute(db);
res = stmt->executeQuery("SELECT * from user");
while (res->next()) {
cout << "\t... MySQL replies: ";
/* Access column data by alias or column name */
cout << res->getString("name") << endl;
cout << "\t... MySQL says it again: ";
/* Access column data by numeric offset, 1 is the first column */
cout << res->getString("password") << endl;
}
delete res;
delete stmt;
delete con;
} catch (sql::SQLException &e) {
cout << "# ERR: SQLException in " << __FILE__;
cout << "(" << __FUNCTION__ << ") on line "<<endl;
cout << "# ERR: " << e.what();
cout << " (MySQL error code: " << e.getErrorCode();
cout << ", SQLState: " << e.getSQLState() << " )" << endl;
cout<<"\n";
}
cout << endl;
return EXIT_SUCCESS;
}
I was confused that why the information was not about the sentence "use account". Instead, it was about "u". Thanks very much.
USER is a reserved word/keyword in MySQL.
You should delimit your field names with backticks to avoid problems:
SELECT * FROM `user`

UDP packets are dropped in OS (asio is used)

I am developing client-server application which transfers data via UDP.
I am facing the problem of dropped packets. I added socket buffer checking to detect potential overflow. Also my app checks sequence of received numbers in packets. Packets have fixed size. If free space of socket buffer is less than threshold (size of 3 packets for example) then "Critical level of buffer" message is logged. If number of packet is skipped in sequence then corresponding message is logged. There is code:
UdpServer::UdpServer(asio::io_service& io, uint16_t port, uint32_t packetSize) : CommunicationBase(io, port),
m_socket(io, asio::ip::udp::endpoint(asio::ip::address_v6::any(), m_port))
{
m_buffer = new uint8_t[packetSize];
m_packetSize = packetSize;
m_socketBufferSize = m_packetSize * 32;
m_criticalLevel = 5 * m_packetSize;
asio::ip::udp::socket::receive_buffer_size recieveBuffSize(m_socketBufferSize);
m_socket.set_option(recieveBuffSize);
}
UdpServer::~UdpServer()
{
std::free(m_buffer);
}
void UdpServer::StartReceive(std::function<void(uint8_t* buffer, uint32_t bytesCount)> receiveHandler)
{
m_onReceive = receiveHandler;
Receive();
}
inline void UdpServer::Receive()
{
m_socket.async_receive(asio::null_buffers(), [=](const boost::system::error_code& error, size_t bytesCount)
{
OnReceive(bytesCount, error);
});
}
void UdpServer::OnReceive(size_t bytesCount, const boost::system::error_code& error)
{
static uint16_t lastSendNum = 65535;
uint16_t currentNum = 0;
uint16_t diff = 0;
if (error)
{
if (error == asio::error::operation_aborted)
{
logtrace << "UDP socket reports operation aborted, terminating";
return;
}
logerror << "UDP socket error (ignoring): " << error.message();
}
else
{
asio::ip::udp::endpoint from;
boost::system::error_code receiveError;
size_t bytesRead = 0;
size_t bytesAvailable = m_socket.available();
while (bytesAvailable > 0)
{
if (m_socketBufferSize - bytesAvailable < m_criticalLevel)
{
logwarning << "Critical buffer level!";
}
bytesRead = m_socket.receive(asio::buffer(m_buffer, m_packetSize), 0, receiveError);
if (receiveError)
{
logerror << "UDP socket error: " << receiveError.message();
break;
}
currentNum = *reinterpret_cast<uint16_t*>(m_buffer);
diff = currentNum - lastSendNum;
if (diff != 1)
{
logdebug << "Chunk skipped: " << diff << ". Last " << lastSendNum << " next " << currentNum;
}
lastSendNum = currentNum;
if (m_onReceive)
{
m_onReceive(m_buffer, bytesRead);
}
bytesAvailable = m_socket.available();
}
}
Receive();
}
Even if checking of buffer status and packet processing m_onReceive are disabled and bytesAvailable > 0 replaced with true, udp packets are dropped. Speed rate is ~71 Mb/s via 1Gb Ethernet.
Windows 10 is used. Also I checked netstat -s result: no reassembly failures. Socket buffer is never being overflowed.

Why would connect() give intermittent EINVAL on port to FreeBSD?

I have in my C++ application a failure that arose upon porting to 32 bit FreeBSD 8.1 from 32 bit Linux. I have a TCP socket connection which fails to connect. In the call to connect(), I got an error result with errno == EINVAL which the man page for connect() does not cover.
What does this error mean, which argument is invalid? The message just says: "Invalid argument".
Here are some details of the connection:
family: AF_INET
len: 16
port: 2357
addr: 10.34.49.13
It doesn't always fail though. The FreeBSD version only fails after letting the machine sit idle for several hours. But after failing once, it works reliably until you let it sit idle again for a prolonged period.
Here is some of the code:
void setSocketOptions(const int skt);
void buildAddr(sockaddr_in &addr, const std::string &ip,
const ushort port);
void deepBind(const int skt, const sockaddr_in &addr);
void
test(const std::string &localHost, const std::string &remoteHost,
const ushort localPort, const ushort remotePort,
sockaddr_in &localTCPAddr, sockaddr_in &remoteTCPAddr)
{
const int skt = socket(AF_INET, SOCK_STREAM, 0);
if (0 > skt) {
clog << "Failed to create socket: (errno " << errno
<< ") " << strerror(errno) << endl;
throw;
}
setSocketOptions(skt);
// Build the localIp address and bind it to the feedback socket. Although
// it's not traditional for a client to bind the sending socket to a the
// local address, we do it to prevent connect() from using an ephemeral port
// which (our site's firewall may block). Also build the remoteIp address.
buildAddr(localTCPAddr, localHost, localPort);
deepBind(skt, localTCPAddr);
buildAddr(remoteTCPAddr, remoteHost, remotePort);
clog << "Info: Command connect family: "
<< (remoteTCPAddr.sin_family == AF_INET ? "AF_INET" : "<unknown>")
<< " len: " << int(remoteTCPAddr.sin_len)
<< " port: " << ntohs(remoteTCPAddr.sin_port)
<< " addr: " << inet_ntoa(remoteTCPAddr.sin_addr) << endl;
if (0 > ::connect(skt, (sockaddr*)& remoteTCPAddr, sizeof(sockaddr_in)))) {
switch (errno) {
case EINVAL: {
int value = -1;
socklen_t len = sizeof(value);
getsockopt(skt, SOL_SOCKET, SO_ERROR, &value, &len);
cerr << "Error: Command connect failed on local port "
<< getLocFbPort()
<< " and remote port " << remotePort
<< " to remote host '" << remoteHost
<< "' family: "
<< (remoteTCPAddr.sin_family == AF_INET ? "AF_INET" : "<unknown>")
<< " len: " << int(remoteTCPAddr.sin_len)
<< " port: " << ntohs(remoteTCPAddr.sin_port)
<< " addr: " << inet_ntoa(remoteTCPAddr.sin_addr)
<< ": Invalid argument." << endl;
cerr << "\tgetsockopt => "
<< ((value != 0) ? strerror(value): "success") << endl;
throw;
}
default: {
cerr << "Error: Command connect failed on local port "
<< localPort << " and remote port " << remotePort
<< ": (errno " << errno << ") " << strerror(errno) << endl;
throw;
}
}
}
}
void
setSocketOptions(int skt)
{
// See page 192 of UNIX Network Programming: The Sockets Networking API
// Volume 1, Third Edition by W. Richard Stevens et. al. for info on using
// ::setsockopt().
// According to "Linux Socket Programming by Example" p. 319, we must call
// setsockopt w/ SO_REUSEADDR option BEFORE calling bind.
int so_reuseaddr = 1; // Enabled.
int reuseAddrResult
= ::setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr,
sizeof(so_reuseaddr));
if (reuseAddrResult != 0) {
cerr << "Failed to set reuse addr on socket.";
throw;
}
// For every two hours of inactivity, a keepalive occurs.
int so_keepalive = 1; // Enabled. See page 200 for info on SO_KEEPALIVE.
int keepAliveResult =
::setsockopt(skt, SOL_SOCKET, SO_KEEPALIVE, &so_keepalive,
sizeof(so_keepalive));
if (keepAliveResult != 0) {
cerr << "Failed to set keep alive on socket.";
throw;
}
struct linger so_linger;
so_linger.l_onoff = 1; // Turn linger option on.
so_linger.l_linger = 5; // Linger time in seconds. (See page 202)
int lingerResult
= ::setsockopt(skt, SOL_SOCKET, SO_LINGER, &so_linger,
sizeof(so_linger));
if (lingerResult != 0) {
cerr << "Failed to set linger on socket.";
throw;
}
// Disable the Nagel algorithm on the command channel. SOL_TCP is not
// defined on FreeBSD
#ifndef SOL_TCP
#define SOL_TCP (::getprotobyname("TCP")->p_proto)
#endif
unsigned int tcpNoDelay = 1;
int noDelayResult
= ::setsockopt(skt, SOL_TCP, TCP_NODELAY, &tcpNoDelay,
sizeof(tcpNoDelay));
if (noDelayResult != 0) {
cerr << "Failed to set tcp no delay on socket.";
throw;
}
}
void
buildAddr(sockaddr_in &addr, const std::string &ip, const ushort port)
{
memset(&addr, 0, sizeof(sockaddr_in)); // Clear all fields.
addr.sin_len = sizeof(sockaddr_in);
addr.sin_family = AF_INET; // Set the address family
addr.sin_port = htons(port); // Set the port.
if (0 == inet_aton(ip.c_str(), &addr.sin_addr)) {
cerr << "BuildAddr IP.";
throw;
}
};
void
deepBind(const int skt, const sockaddr_in &addr)
{
// Bind the requested port.
if (0 <= ::bind(skt, (sockaddr *)&addr, sizeof(addr))) {
return;
}
// If the port is already in use, wait up to 100 seconds.
int count = 0;
ushort port = ntohs(addr.sin_port);
while ((errno == EADDRINUSE) && (count < 10)) {
clog << "Waiting for port " << port << " to become available..."
<< endl;
::sleep(10);
++count;
if (0 <= ::bind(skt, (sockaddr*)&addr, sizeof(addr))) {
return;
}
}
cerr << "Error: failed to bind port.";
throw;
}
Here is example output when EINVAL (it doesn't always fail here, sometimes it succeeds and fails on the first packet sent over the socket getting scrambled):
Info: Command connect family: AF_INET len: 16 port: 2357 addr: 10.34.49.13
Error: Command connect failed on local port 2355 and remote port 2357 to remote host '10.34.49.13' family: AF_INET len: 16 port: 2357 addr: 10.34.49.13: Invalid argument.
getsockopt => success
I figured out what the issue was, I was first getting a ECONNREFUSED, which on Linux I can just retry the connect() after a short pause and all is well, but on FreeBSD, the following retry of connect() fails with EINVAL.
The solution is when ECONNREFUSED to back up further and instead start retrying back to beginning of test() definition above. With this change, the code now works properly.
It's interesting that the FreeBSD connect() manpage doesn't list EINVAL. A different BSD manpage states:
[EINVAL] An invalid argument was detected (e.g., address_len is
not valid for the address family, the specified
address family is invalid).
Based on the disparate documentation from the different BSD flavours floating around, I would venture that there may be undocumented return code possibilities in FreeBSD, see here for example.
My advice is to print out your address length and the sizeof and contents of your socket address structure before calling connect - this will hopefully assist you to find out what's wrong.
Beyond that, it's probably best if you show us the code you use to set up the connection. This includes the type used for the socket address (struct sockaddr, struct sockaddr_in, etc), the code which initialises it, and the actual call to connect. That'll make it a lot easier to assist.
What’s the local address? You’re silently ignoring errors from bind(2), which seems like not only bad form, but could be causing this issue to begin with!