main.cpp:
#include <sys/socket.h>
#include <string>
#include <iostream>
#include <unistd.h>
int main() {
int s;
s = socket( AF_UNIX, SOCK_STREAM, 0 );
int val = 0;
socklen_t size = (socklen_t)sizeof(val);
if ( setsockopt( s, SOL_SOCKET, SO_SNDBUF, &val, size ) == -1 ) {
std::cerr << "Set sock option failed" << std::endl;
std::cerr << "Errno: " << errno << std::endl << "Error Message: " << std::strerror(errno) << std::endl;
return -1;
}
return 0;
}
compiled with:
g++ main.cpp
results in:
Set sock option failed
Errno: 22
Error Message: Invalid argument
This same code runs perfectly on linux, but gives the above error on macOS (10.15.7, g++ Apple clang version 12.0.0). Additionally, with other options (SO_DEBUG for example) it completes. What could be causing this?
Related
I would like to implement the solution of user #bunto1 from this post (What is the easiest way to get PPP0 interface Tx/Rx bytes in a custom C/C++ program?) in my code:
It consists in reading RX and TX from the "ppp0" interface.
#include <linux/if_ppp.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
Code:
auto sockfd = ::socket(PF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
std::cout << "couldn't open socket : " << errno << std::endl;
return;
}
ifreq req {};
ppp_stats stats {};
req.ifr_data = reinterpret_cast<caddr_t>(&stats);
::strncpy(&req.ifr_name[0], "ppp0", sizeof(req.ifr_name));
auto ret = ::ioctl(sockfd, SIOCGPPPSTATS, &req);
if (ret < 0) {
std::cout << "couldn't get PPP statistics : " << errno << std::endl;
} else {
std::cout << "received bytes : " << stats.p.ppp_ibytes << std::endl;
std::cout << "sent bytes : " << stats.p.ppp_obytes << std::endl;
}
auto ret = ::close(sockfd);
if (ret != 0) {
std::cout << "couldn't close socket : " << errno << std::endl;
}
Unfortunately, when I wrote this code for myself, the compiler reports an error:
/usr/include/linux/if_ppp.h:92:7: error: use of enum ‘NPmode’ without previous declaration
enum NPmode mode;
^
/usr/include/linux/if_ppp.h:103:16: error: field ‘b’ has incomplete type ‘ifreq’
struct ifreq b;
^
/usr/include/linux/if_ppp.h:104:19: error: field ‘stats’ has incomplete type ‘ppp_stats’
struct ppp_stats stats; /* statistic information */
^
/usr/include/linux/if_ppp.h:108:21: error: field ‘b’ has incomplete type ‘ifreq’
struct ifreq b;
^
usr/include/linux/if_ppp.h:109:24: error: field ‘stats’ has incomplete type ‘ppp_comp_stats’
struct ppp_comp_stats stats;
I noticed that this is due to the inclusion of a header file:
#include <linux/if_ppp.h>
What could this be caused by?
I'm using Ubuntu 18.04/gcc 7.3/OpenSSL 1.1.0g to make C++ app performing TLS/SSL connection with non-blocking BIO API.
When BIO_do_connect() fails connecting, e.g. if using wrong host name or port, there is no errors reported by OpenSSL. ERR_get_error() returns zero and ERR_print_errors_xx() doesn't print anything.
So the question is - how to get actual connection failure reason, e.g. 'Connection refused' or 'Host not resolved' etc?
Used code snippet below:
#include <cstdio>
#include <cstring>
#include <iostream>
#include "openssl/bio.h"
#include "openssl/err.h"
#include "openssl/ssl.h"
int main(int argc, char *argv[])
{
OPENSSL_init_ssl(OPENSSL_INIT_SSL_DEFAULT, nullptr);
std::cout << OpenSSL_version(OPENSSL_VERSION) << std::endl;
SSL_CTX* ctx = SSL_CTX_new(TLS_client_method());
if (!ctx)
{
std::cerr << "Error creating SSL context:" << std::endl;
ERR_print_errors_fp(stderr);
return 1;
}
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
if(!SSL_CTX_load_verify_locations(ctx,
"/etc/ssl/certs/ca-certificates.crt",
nullptr))
{
std::cerr << "Error loading trust store into SSL context" << std::endl;
ERR_print_errors_fp(stderr);
return 1;
}
BIO* cbio = BIO_new_ssl_connect(ctx);
SSL* ssl = nullptr;
BIO_get_ssl(cbio, &ssl);
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
BIO_set_conn_hostname(cbio, "not_actually_existing_host.com:https");
BIO_set_nbio(cbio, 1);
std::cout << "Start connecting" << std::endl;
next:
if (BIO_do_connect(cbio) <= 0)
{
if (!BIO_should_retry(cbio))
{
std::cerr << "Error attempting to connect:" << std::endl;
ERR_print_errors_fp(stderr); // <---- PRINTS NOTHING!!!
BIO_free_all(cbio);
SSL_CTX_free(ctx);
return 1;
}
else goto next;
}
std::cout << "Connected OK" << std::endl;
BIO_free_all(cbio);
SSL_CTX_free(ctx);
return 0;
}
This approach finally works for me:
const auto sysErrorCode = errno;
const auto sslErrorCode = ERR_get_error();
std::string errorDescription;
if (sslErrorCode != 0) errorDescription = ERR_error_string(sslErrorCode, nullptr);
if (sysErrorCode != 0)
{
if (!errorDescription.empty()) errorDescription += '\n';
errorDescription += "System error, code=" + std::to_string(sysErrorCode);
errorDescription += ", ";
errorDescription += strerror(sysErrorCode);
}
I'm starting a simple socket server on a separate thread, and trying to connect to it using netcat on the main thread. This is the code:
#include <cstdlib>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
void* callback(void*);
bool isServerReady = false;
int main()
{
pthread_t thread;
int result = pthread_create(&thread, 0, callback, 0);
if (result != 0) {
cout << "[ERROR] Unable to create thread" << endl;
}
while (!isServerReady) {
}
int returnValue = system("echo TEST | netcat localhost 1234");
cout << "Return value: " << returnValue << endl;
return 0;
}
void* callback(void* threadId)
{
int serverSocketId = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocketId == -1) {
cout << "[SERVER ERROR] Unable to create server socket." << endl;
return (void*)-1;
}
int serverPort = 1234;
struct sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(serverPort);
serverAddress.sin_addr.s_addr = INADDR_ANY;
int bindReturn = bind(serverSocketId, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
if (bindReturn == -1) {
cout << "[SERVER ERROR] Unable to bind server socket." << endl;
return (void*) -1;
}
isServerReady = true;
int waitQueueSize = 5;
listen(serverSocketId, waitQueueSize);
struct sockaddr_in clientAddress;
socklen_t clientAddressSize = sizeof(clientAddress);
int clientSocketId = accept(serverSocketId, (struct sockaddr*)&clientAddress, &clientAddressSize);
if (clientSocketId == -1) {
cout << "[SERVER ERROR] Unable to create client socket." << endl;
return (void*)-1;
}
char clientBuffer[256];
bzero(clientBuffer, 256);
int charsRead = read(clientSocketId, clientBuffer, 255);
if (charsRead == -1) {
cout << "[SERVER ERROR] Unable to read client socket." << endl;
return (void*)-1;
}
string serverMessage = "You wrote: ";
serverMessage.append(clientBuffer);
int charsWritten = write(clientSocketId, (char*)serverMessage.c_str(), (int)serverMessage.length());
if (charsWritten == -1) {
cout << "[SERVER ERRROR] Error writing to client socket." << endl;
return (void*)-1;
}
int closeReturn = close(serverSocketId);
if (closeReturn == -1) {
cout << "[SERVER ERROR] Error closing server socket." << endl;
return (void*)-1;
}
return (void*)0;
}
However, the system function never returns, making the program hang: the server's response "You wrote: TEST" is correctly printed on the console, but after that the program just hangs, without reaching the line that prints the return value. If I extract the same server code into another program, launch it, and use the same netcat call from the command line, I get the same response message, and then netcat exits without me being required to do anything.
This is the compilation command:
g++ -std=c++11 test.cpp -o test -lpthread && ./test
and compiler version:
g++ (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4
Why do you think netcat is not returning when called from inside system()?
Thanks to #kfsone, the problem was just that my server never closed the client socket, thus preventing the client netcat to realize that the server wasn't listening any more, and making it wait for no reason indefinitely. To solve this:
// ...
string serverMessage = "You wrote: ";
serverMessage.append(clientBuffer);
int charsWritten = write(clientSocketId, (char*)serverMessage.c_str(), (int)serverMessage.length());
if (charsWritten == -1) {
cout << "[SERVER ERRROR] Error writing to client socket." << endl;
return (void*)-1;
}
// ADDED THIS:
int closeClientReturn = close(clientSocketId);
if (closeClientReturn == -1) {
cout << "[SERVER ERROR] Error closing client socket." << endl;
return (void*)-1;
}
int closeReturn = close(serverSocketId);
if (closeReturn == -1) {
cout << "[SERVER ERROR] Error closing server socket." << endl;
return (void*)-1;
}
return (void*)0;
The following code works just fine when linking with Oracle client 11g but if I compile the same linking with Oracle 12c libraries I receive the error EINVAL Invalid argument - errno 22.
#include <sys/types.h>
#include <aio.h>
#include <fcntl.h>
#include <errno.h>
#include <iostream>
using namespace std;
const int SIZE_TO_READ = 100;
int main()
{
// open the file
int file = open("blah.txt", O_RDONLY, 0);
if (file == -1)
{
cout << "Unable to open file!" << endl;
return 1;
}
// create the buffer
char* buffer = new char[SIZE_TO_READ];
// create the control block structure
aiocb cb;
memset(&cb, 0, sizeof(aiocb));
cb.aio_nbytes = SIZE_TO_READ;
cb.aio_fildes = file;
cb.aio_offset = 0;
cb.aio_buf = buffer;
// read!
if (aio_read(&cb) == -1)
{
cout << "Unable to create request!" << endl;
close(file);
}
cout << "Request enqueued!" << endl;
// wait until the request has finished
while(aio_error(&cb) == EINPROGRESS)
{
cout << "Working..." << endl;
}
// success?
int numBytes = aio_return(&cb);
if (numBytes != -1)
cout << "Success!" << endl;
else
cout << "Error!" << endl;
// now clean up
delete[] buffer;
close(file);
return 0;
}
Then to compile I first set the env variables
export ICLIBHOME=/u01/oracle/product/Linux/2.6/x86_64/clients/12.1.0.2/64bit/client/lib
export LD_LIBRARY_PATH=${ICLIBHOME}
Afterwards I compile and execute my compiled file but I get the error
g++ myaio.cpp -o myaio -lrt -L${ICLIBHOME} -lclntsh
./myaio
Unable to create request 22
I am writing a packet sniffer in C++ utilizing streams instead of printf() to store and create output. The problem I've run into is that recvfrom() seems to fail and return -1 when I have two or more statements that generate output using a stream.
If I comment one of the two output generating statements, the program runs fine. Through trial and error, I've found that by removing the std::setw() from the std::cout statement, it will work correctly and display both the packet and the "beef" message.
Any ideas or help would be much appreciated as I am at a loss and considering reverting back to using printf() since it never had this problem (and is faster than a stream). I admit, this is really the first time I have ever used ostringstream and I may be using it incorrectly.
My simplified source code:
#include <iostream>
#include <sstream>
#include <iomanip>
#include <string>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <linux/if_packet.h>
std::string BufferInHex( unsigned char * buffer, int length )
{
std::ostringstream out;
for( int i = 0; i < length; i ++ ) {
if( i % 16 == 0 && i != 0 ) {
out << "\n";
}
else if( i % 8 == 0 && i != 0 ) {
out << " ";
}
out << std::hex;
out << std::setfill('0') << std::setw(2) << static_cast<unsigned>(buffer[i]) << " ";
out << std::dec;
}
return out.str();
}
int main( void )
{
struct sockaddr_ll saddr = {0};
socklen_t saddr_size = sizeof(saddr);
unsigned char packet[1500] = {0};
int sockFd = socket( AF_PACKET, SOCK_RAW, htons(ETH_P_ALL) );
if( sockFd < 0 ) {
std::cerr << "Error creating socket!\n";
return 1;
}
int data_size = recvfrom( sockFd, packet, sizeof( packet ), 0, (struct sockaddr*)&saddr, &saddr_size );
if( data_size == -1 ) {
std::cerr << "Error in recvfrom()\n";
return 2;
}
std::cout << std::hex;
std::cout << std::setw( 8 ) << ntohs( 0xADDE ) << "\n";
std::cout << std::dec;
std::cout << BufferInHex( packet, data_size ) << "\n";
return 0;
}
It is being compiled with g++ on Centos 6.4 kernel 2.6.32 using the following command:
g++ sniff.cpp -o sniff -Wall
Thanks for any ideas or help,
Jeremiah