Select Git revision
configure.sh
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
tcpsocket.cpp 5.18 KiB
/*
* Copyright 2020 Stichting Nederlandse Wetenschappelijk Onderzoek Instituten,
* ASTRON Netherlands Institute for Radio Astronomy
* Licensed under the Apache License, Version 2.0 (the "License");
*
* you may not use this file except in compliance with the License.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* See ../../LICENSE.txt for more info.
*/
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <arpa/inet.h> // htons
#include <sys/types.h>
#include <sys/wait.h>
#include <netdb.h>
#include <fcntl.h>
//#include <syslog.h>
#include <errno.h>
#include <iostream>
#include <sstream>
#include <string.h>
#include <stdexcept>
#include "tcpsocket.h"
/*
TCP Server Socket listens to port p and binds to interface iface.
Set iface="" to not bind to an interface.
*/
TCPSSocket::TCPSSocket(uint16_t p, const char* iface, int maxservers)
{
port = p;
MaxServers = maxservers;
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock < 0)
throw runtime_error("TCPSSocket: socket creation error");
int val = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
close(sock);
cerr << "Error: " << strerror(errno) << endl;
throw runtime_error("TCPSSocket: cannot set socket option SO_REUSEADDR");
}
/* Give the socket a name. */
name.sin_family = AF_INET;
name.sin_port = htons (port);
name.sin_addr.s_addr = htonl (INADDR_ANY);
if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
close(sock);
cerr << "Error: " << strerror(errno) << endl;
throw runtime_error("TCPSSocket: cannot bind socket");
}
}
TCPSSocket::~TCPSSocket()
{
close(sock);
}
int TCPSSocket::listen(void)
{
ostringstream strs;
printf("Listening to tcp port %d\n",port);
// syslog(LOG_INFO,"Listening to tcp port %d\n",port);
if (::listen (sock, 1) < 0)
throw runtime_error("TCPSSocket::listen: cannot put socket into listening state");
/* Block until input arrives on the server socket. */
int nsock;
struct sockaddr_in clientname;
socklen_t size = sizeof (clientname);
nsock = accept (sock,(struct sockaddr *) &clientname,&size);
if (nsock < 0) {
cerr << "Error TCPSSocket::listen() accept(): " << strerror(errno) << endl;
exit(-1);
}
struct hostent *he;
he = gethostbyaddr(&clientname.sin_addr, sizeof clientname.sin_addr, AF_INET);
strs << "Server: Client connect from host "
<< (he ? he->h_name : inet_ntoa (clientname.sin_addr)) << " (" << inet_ntoa (clientname.sin_addr)
<< "):" << ntohs(clientname.sin_port) << endl;
// syslog(LOG_INFO,"%s",strs.str().c_str());
return nsock;
}
TCPCSSocket::TCPCSSocket(int s)
{
sock = s;
}
TCPCSSocket::~TCPCSSocket()
{
close(sock);
}
size_t TCPCSSocket::rx(unsigned char *buf, size_t len)
/*
Receive max len bytes from a TCP socket
This one stops after one packet and returns the
number of actual received bytes
*/
{
size_t nrx = 0;
ssize_t ret;
do {
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
// No time out
if(select(sock + 1, &readfds, NULL, NULL, NULL) == -1) {
throw runtime_error("TCPCSSocket::rx: select error");
}
if FD_ISSET(sock, &readfds) {
ret = recvfrom(sock, buf, len, 0, NULL, NULL);
if(ret == -1) {
throw runtime_error("TCPCSSocket::rx(): recvfrom=-1 error");
} else if(ret == 0) {
throw runtime_error("TCPCSSocket::rx(): recvfrom=0 peer orderly shutdown");
}
nrx += ret;
break;
}
} while (1);
return nrx;
}
size_t TCPCSSocket::_rx(unsigned char *buf, size_t len)
/*
Receive len bytes from a TCP socket
*/
{
size_t nrx = 0;
ssize_t ret;
//struct timeval timeout;
//timeout.tv_sec = timeoutms / 1000;
//timeout.tv_usec = ( timeoutms % 1000 ) * 1000;
// Receive a datagram from a tx source
do {
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
// No time out
if(select(sock + 1, &readfds, NULL, NULL, NULL) == -1) {
throw runtime_error("TCPCSSocket::_rx: select error");
}
if FD_ISSET(sock, &readfds) {
ret = recvfrom(sock, &buf[nrx], len-nrx, 0, NULL, NULL);
if(ret == -1) {
throw runtime_error("TCPCSSocket::_rx(): recvfrom=-1 error");
} else if(ret == 0) {
throw runtime_error("TCPCSSocket::_rx(): recvfrom=0 peer orderly shutdown");
}
nrx += ret;
}
if (nrx==len)
break;
} while (1);
return nrx;
}
size_t TCPCSSocket::tx(const unsigned char* mes, size_t len)
{
int ntxbytes = write(sock, mes, len);
if (ntxbytes < 0)
throw runtime_error("TCPCSSocket::tx(): could not send message");
return ntxbytes;
}