I'm trying to create server/client communication and it faileson the connect function with errno 88. I checked if the socketfd is valid (because this errno means that I'm trying to make socket operation on non socket object).
int main (int argc, char *argv[])
{
// Validity check
if (argc != VALID_ARG_NUM) {
std::cout << INVALID_ARG;
return 0; // todo - return 0 is correct??
}
int port;
struct sockaddr_in server_address;
// server_address initialization.
server_address.sin_family = AF_INET;
server_address.sin_port = htons((uint32_t)atof(argv[3]));
server_address.sin_addr.s_addr = inet_addr(argv[2]);
memset(&(server_address.sin_zero), '\0', sizeof(server_address));
// Create the client socket.
if (sockfd = socket(AF_INET, SOCK_STREAM, 0) < 0) {
std::cout << "ERROR: socket " << errno << "." << std::endl;
exit(1);
}
// Connect to server.
if (connect(sockfd, (struct sockaddr *)&server_address, sizeof(server_address)) < 0) {
std::cout << "ERROR: connect " << errno << "." << std::endl;
std::cout << CON_FAIL;
close(sockfd);
exit(1);
}
.......
thank you.
The precedence of the statement
sockfd = socket(AF_INET, SOCK_STREAM, 0) < 0
is
sockfd = ((socket(AF_INET, SOCK_STREAM, 0)) < 0)
and you are therefore assigning a boolean, which is implicitly converted to an integer (or whatever type sockfd has). What you probably meant was instead
(sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0
I think this part is causing buffer overrun:
memset(&(server_address.sin_zero), '\0', sizeof(server_address));
You should zero the whole struct before writing somefields:
struct sockaddr_in server_address;
// server_address initialization.
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
Broken pipe usually means that remote peer closes connection. Are you sure your server code is OK? Maybe it just do something like this?
int main()
{
...
listen();
accept();
return 0;//procees exits and therefore brakes connection
}
Related
I'm working on a multithreaded UDP listener and I'm stuck in a problem that definitely surpasses me.
So, I'm required to receive huge amounts of UDP packets in several ports. Locally, the best solution for me was to call non blocking recvfrom in as much threads as ports I'm listening (select and poll were too slow for my requirements). I'm using a thread pool manager, it simply calls on threads and queues tasks. Here's the code:
void receiveFromSocket(void * arguments){
sockaddr_in client; // Local
socklen_t clientSize = sizeof(client);
memset(&client, 0, sizeof(client));
struct arg_struct_listenPort *args2 = (struct arg_struct_listenPort *)arguments;
int fd = args2->arg_fd;
int port = args2->arg_port;
for(;;) {
char buf[158];
memset(buf,0,158*sizeof(char));
int n = recvfrom(fd, (char * ) buf, 158, MSG_DONTWAIT, ( struct sockaddr *) &client, &clientSize);
if(n == -1){
//cerr << "Error while receiving from client: " << errno << endl;
continue;
}
if(n != 158){
cerr << "Discarded message since it's not 158 bytes." << endl;
continue;
}
struct arg_struct args;
args.arg_port = port;
memcpy(args.buf,buf,158);
thpool_add_work(globals.thpool, socketThread, (void*)(&args));
}
}
/// Runs the Socket listener
int network_accept_any()
{
vector<int>::iterator i;
for(i = globals.fds.begin(); i != globals.fds.end(); i++){
int port = distance(globals.fds.begin(),i);
struct arg_struct_listenPort args;
args.arg_fd = *i;
args.arg_port = globals.cmnSystemCatalogs[port].diag_port;
thpool_add_work(globals.thpool, receiveFromSocket, (void*)(&args));
}
cout << "Listening threads created..." << endl;
return 0;
}
This works perfectly fine locally. But when I compile it on a production environment, some ports listen the packets and other's simply don't! And the working ports change in each execution. I can , confirm that it is not a firewall problem. I also can clearly see the packets through Wireshark. I can receive packets on those ports through netcat. Netstat shows all ports open.
My local environment is an Ubuntu 18.04 VM, and the production environment is a Debian 9.8.
Here's how I call the sockets:
int lSocket(int port) {
//Crear Socket
int listening = socket(AF_INET, SOCK_DGRAM, 0);
if (listening == -1) {
cerr << "No se puede crear el socket";
exit(EXIT_FAILURE);
}
//Enlazar socket a un IP / puerto
struct sockaddr_in hint;
memset(&hint, 0, sizeof(hint));
hint.sin_family = AF_INET; //IPv4
hint.sin_port = htons(port); //Port
hint.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(listening, (struct sockaddr*)&hint, sizeof(hint)) == -1) { //Enlaza las opciones definidas al socket
cerr << "No se puede enlazar IP/puerto" << endl;
exit(EXIT_FAILURE);
}
return listening;
}
Any advise is greatly appreciated!
EDIT:
As suggested, I tried switching to blocking I/O, but the main issue remains. Still not receiving at all the opened ports.
What an amazing welcome!
#molbdnilo was absolutely right:
You're using pointers to objects whose lifetime has ended (&args).
This has undefined behaviour - it might appear to work, but it's a bug
that needs a-fixin'.
Here's the fixed code. Gotta be careful when feeding arguments to threads!
void receiveFromSocket(void * arguments){
sockaddr_in client; // Local
socklen_t clientSize = sizeof(client);
memset(&client, 0, sizeof(client));
struct arg_struct_listenPort *args2 = (struct arg_struct_listenPort *)arguments;
int fd = args2->arg_fd;
int port = args2->arg_port;
for(;;) {
char buf[158];
memset(buf,0,158*sizeof(char));
int n = recvfrom(fd, (char * ) buf, 158, MSG_WAITALL, ( struct sockaddr *) &client, &clientSize);
if(n == -1){
cerr << "Error while receiving from client: " << errno << endl;
continue;
}
if(n != 158){
cerr << "Discarded message since it's not 158 bytes." << endl;
continue;
}
arg_struct *args = new arg_struct;
args->arg_port = port;
memcpy(args->buf,buf,158);
thpool_add_work(globals.thpool, socketThread, (void*)(args));
}
}
/// Runs the Socket listener
int network_accept_any()
{
vector<int>::iterator i;
for(i = globals.fds.begin(); i != globals.fds.end(); i++){
int port = distance(globals.fds.begin(),i);
arg_struct_listenPort *args = new arg_struct_listenPort;
args->arg_fd = *i;
args->arg_port = globals.cmnSystemCatalogs[port].diag_port;
thpool_add_work(globals.thpool, receiveFromSocket, (void*)(args));
}
cout << "Listening threads created..." << endl;
return 0;
}
Also, I'll keep an eye on #John Bollinger 's and #Superlokkus comments.
Thank you all!
I write a method, that creates a socket, connect it to the endpoint, and then returns its descriptor:
static int open_socket(const char* host, unsigned short port)
{
#ifdef USE_IPV4
struct hostent* _hostent;
struct sockaddr_in _sockaddr_in;
// Variables
size_t sockaddr_len;
int sock_family;
int sock_type;
int sock_protocol;
int sockfd;
_hostent = gethostbyname(host);
if (_hostent == (struct hostent*) 0)
{
// Not Found
}
_sockaddr_in.sin_family = AF_INET;
sock_family = AF_INET;
sock_type = SOCK_STREAM;
sock_protocol = IPPROTO_TCP;
sockaddr_len = sizeof(_sockaddr_in);
(void*) memmove(&_sockaddr_in, _hostent->h_addr, _hostent->h_length);
_sockaddr_in.sin_port = htons(port);
// Now create socket
sockfd = socket(sock_family, sock_type, sock_protocol);
if (sockfd < 0)
{
// "Internal Error"
}
if (connect(sockfd, (struct sockaddr*) &_sockaddr_in, sockaddr_len) < 0)
{
std::cerr << strerror(errno) << std::endl;
std::cerr << "Endpoint is unavailable" << std::endl;
return 0;
// "Unavailable"
}
return sockfd;
#endif
}
The error occures when i try to connect socket. strerror(errno) returns "Address family not supported by protocol". I cannot figure out why it happens, because in other samples AF_INET fine works with IPPROTO_TCP
You need to store the address in sockaddr_in::sin_addr instead. You are overwriting the entire struct (starting from the sin_family) when you call memmove(&_sockaddr_in, ...).
I have this code
Server:
//"sock" has already been created with no problem and binding as well
void Connection::bind_connection(int port){
cout << "Port " << port << endl;
server.sin_family = AF_INET ;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(port);
/* Bind socket to address */
struct sockaddr *serverptr = ( struct sockaddr *) &server;
if ( bind ( sock , serverptr , sizeof(server) ) < 0) {
perror("Binding error"); exit(BE);
}
cout << "Server binding completed!" << endl;
}
struct sockaddr_in client ;
socklen_t clientlen ;
struct sockaddr * clientptr =( struct sockaddr *) &client ;
if ( listen (sock , MAX_CONNECTIONS) < 0) {perror("listening error"); exit(LE);}
cout << "Listening for connections to port " << port << endl;
while (1) {
/* accept connection */
if (( newsock = accept ( sock , clientptr , &clientlen ) ) < 0) {
perror("Accepting error"); cout << "Errno = " << errno << endl; exit(AE);
}
//Code
....
}
and
Client:
//struct sockaddr_in server; <--- declared as data member of class "Connection"
//"sock" has already been created with no problem
void Connection::do_connect(){
struct sockaddr *serverptr = ( struct sockaddr *) &server;
if ( connect ( sock , serverptr , sizeof (server) ) < 0)
perror("client connect"); exit(CE);
cout << "Client connecting to the server" << endl;
}
and I get the above message. Most of the code is copied from the lesson slides but modified for my needs. Googling the problem it seems that I give wrong size at the syscall(s). Any idea where exactly the problem is? Thanks in advance.
Those lines always exit:
if ( connect ( sock , serverptr , sizeof (server) ) < 0)
perror("client connect"); exit(CE);
You might start to think about using a different indention scheme. Typically one that does not use more then one statement per line.
For the above code a tool like indent would have formatted it like this:
if (connect (sock, serverptr, sizeof (server)) < 0)
perror("client connect");
exit(CE);
This format makes the programming bug obvious.
You didn't initialize clientlen.
socklen_t clientlen = sizeof(client);
You can catch similar problems in future by running your code through valgrind.
As already indicated, you do not seem to be initializing your variables properly. You do not show how you initialize your sockaddr_in structures, which is likely the culprit. A relatively easy way to specify the address for bind() or connect() is to use getaddrinfo()/freeaddrinfo(). From the documentation:
Synopsis
int getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints,
struct addrinfo **res);
void freeaddrinfo(struct addrinfo *res);
Description
Given node and service, which identify an Internet host and a service, getaddrinfo() returns one or more addrinfo structures, each of which contains an Internet address that can be specified in a call to bind(2) or connect(2). ...
The freeaddrinfo()function frees the memory that was allocated for the dynamically allocated linked list res.
As a simple example, here is a function that can connect to a server specified by a string that has the format <servername>:<port>:
int connect_tcp (std::string hostspec) {
struct addrinfo hints = { .ai_flags = AI_NUMERICSERV };
struct addrinfo *res = 0;
std::istringstream ss(hostspec);
std::string node, service;
int sock = -1;
std::getline(ss, node, ':');
std::getline(ss, service, ':');
getaddrinfo(node.c_str(), service.c_str(), &hints, &res);
for (struct addrinfo *rp = res; rp != 0; rp = rp->ai_next) {
if (rp->ai_socktype != SOCK_STREAM) continue;
int sock = socket(rp->ai_family, SOCK_STREAM, 0);
if (sock == -1) continue;
if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
break;
close(sock);
sock = -1;
}
freeaddrinfo(res);
if (sock == -1) errno = EHOSTDOWN;
return sock;
}
The following c++ program should convert each line to uppercase using socket datagram to communicate between two threads.
Example:
Hello World!<return>
HELLO WORLD!
123abc!<return>
123ABC!
<return>
<end program>
The program as written works for me, however if I comment the bugfix() function call in the main the program wait indefinitely after the first line of input.
Example:
Hello World!<return>
<the program wait indefinitely>
This happen on windows 7 with the last update as 10/04/2011 using the last MinGW32.
#include <iostream>
#include <cstdlib>
#include <cctype>
#include <sys/types.h>
#include <winsock.h>
#include <windows.h>
#include <process.h>
using namespace std;
#define CHECK(exp, cond) do { typeof(exp) _check_value_ = exp; check(_check_value_ cond, _check_value_, __LINE__, #exp #cond); } while(0)
template <class T>
void check(bool ok, T value, int line, const char* text) {
if (!ok) {
cerr << "ERROR(" << line << "):" << text << "\nReturned: " << value << endl;
cerr << "errno=" << errno << endl;
cerr << "WSAGetLastError()=" << WSAGetLastError() << endl;
exit(EXIT_FAILURE);
}
}
#define DATA_CAPACITY 1000
#define PORT 23584
#define TEST_IP "192.0.32.10"
#define MYSELF "127.0.0.1"
#define DST_IP MYSELF
sockaddr_in address(u_long ip, u_short port) {
sockaddr_in addr = { };
addr.sin_family = AF_INET;
addr.sin_port = port;
addr.sin_addr.s_addr = ip;
return addr;
}
void __cdecl client_thread(void* args) {
SOCKET s = *(SOCKET*)args;
sockaddr_in addr = address(inet_addr(DST_IP), htons(PORT));
char data[DATA_CAPACITY];
while (1) {
cin.getline(data, DATA_CAPACITY);
int data_len = strlen(data);
CHECK(sendto(s, data, data_len, 0, (sockaddr*)&addr, sizeof addr), >= 0);
CHECK(recvfrom(s, data, DATA_CAPACITY, 0, NULL, NULL), >= 0);
cout << data << endl;
if (data_len == 0)
break;
}
CHECK(closesocket(s), == 0);
}
void __cdecl server_thread(void* args) {
SOCKET s = *(SOCKET*)args;
sockaddr_in addr = address(INADDR_ANY, htons(PORT));
int addr_size = sizeof addr;
CHECK(bind(s, (sockaddr*)&addr, sizeof addr), != SOCKET_ERROR);
char data[DATA_CAPACITY];
while (1) {
int data_len = recvfrom(s, data, DATA_CAPACITY, 0, (sockaddr*)&addr, &addr_size);
CHECK(data_len, >= 0);
for (int i = 0; i < data_len; i++)
if (islower(data[i]))
data[i] = toupper(data[i]);
CHECK(sendto(s, data, data_len, 0, (sockaddr*)&addr, addr_size), >= 0);
if (data_len == 0)
break;
}
CHECK(closesocket(s), == 0);
}
// This function create a TCP connection with www.example.com and the close it
void bugfix() {
SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in addr = address(inet_addr(TEST_IP), htons(80));
connect(s, (sockaddr*)&addr, sizeof addr);
CHECK(closesocket(s), == 0);
}
int main()
{
cout << "Convert text to uppercase, an empty line terminate the program" << endl;
WSADATA wsaData;
CHECK(WSAStartup(MAKEWORD(2, 2), &wsaData), == 0);
SOCKET client = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
SOCKET server = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
CHECK(client, != INVALID_SOCKET);
CHECK(server, != INVALID_SOCKET);
// if this function is not called the program doesn't work
bugfix();
HANDLE hClient = (HANDLE)_beginthread(client_thread, 0, &client);
HANDLE hServer = (HANDLE)_beginthread(server_thread, 0, &server);
HANDLE h[] = { hClient, hServer };
WaitForMultipleObjects(sizeof h / sizeof *h, h, TRUE, INFINITE);
CHECK(WSACleanup(), == 0);
return EXIT_SUCCESS;
}
int data_len = strlen(data);
Tony Hoare called his definition of a NULL pointer his billion dollar mistake. Having strings zero-terminated must be Dennnis Ritchie's ten billion dollar mistake. Add one.
Your program is otherwise an elaborate way to discover that UDP is not a reliable protocol. The network stack is allowed to arbitrarily make UDP packets disappear or reorder them. Which is okay as long as there's another protocol on top of it that detects this, like TCP. You are flying without such bandaids, bugfix() is not actually a workaround.
Use TCP, send the packet length first so that the receiver will know how many bytes are following so you're immune to stream behavior. But more to the point, exchanging data between threads through a socket is a really expensive way to avoid using an array with a mutex. Threads have unfettered access to memory in the process, you don't need an interprocess communication mechanism to get them to exchange data.
I see several problems right off the bat.
I normally don't use IPPROTO_UDP flag to create the socket. Just pass 0 for the protocol parameter to the socket.
SOCKET client = socket(PF_INET, SOCK_DGRAM, 0);
SOCKET server = socket(PF_INET, SOCK_DGRAM, 0);
More important. You need to call "bind" on the client socket in the same way that you do the server socket. If you want the OS to pick a randomly available port for you, you can use 0 as the port value and IPADDR_ANY for the IP address. If you want to know what the OS picked as a local port for you, you can use getsockname. Something like the following:
void __cdecl client_thread(void* args) {
SOCKET s = *(SOCKET*)args;
sockaddr_in addr = address(inet_addr(DST_IP), htons(PORT));
sockaddr_in localAddrBind = address(INADDR_ANY, 0);
sockaddr_in localAddrActual = {};
int length = sizeof(localAddrActual);
int bindRet = bind(s, (sockaddr*)&localAddrBind, sizeof(localAddrBind));
getsockname(s, (sockaddr*)&localAddrActual, &length);
printf("Listening on port %d\n", ntohs(localAddrActual.sin_port));
Ok. So I have a simple client program sending images over UDP to a specified IP address. At the specified IP a server program is listening and should receive the images.
When I try both programs on localhost (i.e. they are both running at 127.0.0.1) it works and the server receives the images. When I try to put the client and the server programs on different PCs in the same network it does not work.
147.232.24.163 is the server IP, 147.232.24.150 is the client IP.
Here is my client program:
// Initialize UDP.
struct sockaddr_in server;
int n_sent;
int socketId = socket(AF_INET, SOCK_DGRAM, 0);
if (socketId < 0)
{
cout << "Problem creating socket." << endl;
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr("147.232.24.163");
// Establish the server port number - we must use network byte order!
server.sin_port = htons(42001);
for ( int iter = 0; iter < 60; iter++ )
{
// load image into jpegBuf
n_sent = sendto(socketId, reinterpret_cast<char*> (&jpegBuf[0]), jpegBuf.size(), 0, (struct sockaddr*) &server, sizeof(server));
if (n_sent < 0) {
cout << "Problem sending data." << endl;
}
}
close(socketId);
Here is my server program:
int main()
{
int bufferSize = 1024000;
int iSockFd = -1;
int iLength = 0;
struct sockaddr_in servAddr, cliAddr;
char buff[bufferSize];
iSockFd=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
memset(&servAddr, 0, sizeof(servAddr));
memset(&cliAddr, 0, sizeof(cliAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr("147.232.24.163");
servAddr.sin_port = htons(42001);
int cliAddrLen = sizeof(struct sockaddr_in);
int bindRet = bind(iSockFd, (struct sockaddr*)&servAddr, sizeof(servAddr));
cout << "Bind returned " << bindRet << endl;
int i = 0;
while (true)
{
int iRcvdBytes=recvfrom(iSockFd, buff, bufferSize, 0,
(struct sockaddr*)&cliAddr, (socklen_t*)&cliAddrLen);
if (0 == i % 5)
{
cout << "Received " << iRcvdBytes << " bytes from the client" << endl;
}
i++;
}
close(iSockFd);
return 0;
}
Any ideas why it does not work? I don't get any error messages.
This is not a solution but your code should be checking iRcvdbytes for error in the same way as the send code checks the result of sendto.
A return of 0 means the socket was closed gracefully (if connection-oriented - that should not apply here), SOCKET_ERROR means an error (in WinSock2 at least).
The socket on the send side needs to be created with IPPROTO_UDP, not 0. This could definitely be causing your failure.