laforge
/
openbts-osmo
Archived
1
0
Fork 0
This repository has been archived on 2022-03-30. You can view files and clone it, but cannot push or open issues or pull requests.
openbts-osmo/public-trunk/smqueue/smnet.h

271 lines
7.0 KiB
C++

/*
* SMlistener.h - Network SIP handler for Short Messages (SMS's) for OpenBTS.
* Written by John Gilmore, July 2009.
*
* Copyright 2009 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* See the COPYING file in the main directory for details.
*/
#ifndef SM_LISTENER_H
#define SM_LISTENER_H
#include <time.h>
#include <string>
#include <iostream>
#include "poll.h"
#include <sys/socket.h>
namespace SMqueue {
class short_msg_pending; // Forward declaration
class SMnet {
public:
struct pollfd *sockets;
nfds_t allocsockets;
nfds_t numsockets;
int mytimeout;
// Other things we remember about each socket
struct extra_sockinfo {
int addrfam;
int socktype;
int protofam;
struct sockaddr_storage addr;
socklen_t addrlen;
} *sockinfo;
// The source (IP-ish) address of the last packet received
char src_addr[200]; // This is overgenerous.
size_t recvaddrlen; // How many bytes of src_addr is valid
// My global hostname, based on my network address.
char *my_network_hostname;
// The last string of random characters returned.
char *random_string;
// The file descriptor we read random numbers from.
int random_fd;
void abfuckingort(); // where did C library abort() go?
/* Constructor */
SMnet() :
sockets (NULL),
allocsockets (0),
numsockets (0),
mytimeout (-1),
sockinfo (NULL),
recvaddrlen (0),
my_network_hostname (0),
random_string (0),
random_fd (0)
{
}
// We have eliminated this default copy-constructor, by making it
// private.
private:
SMnet(const SMnet &) :
sockets (NULL),
allocsockets (0),
numsockets (0),
mytimeout (-1),
sockinfo (NULL),
recvaddrlen (0),
my_network_hostname (0),
random_string (0),
random_fd (0)
{
abfuckingort();
}
/* Disable operator= so that pointers don't get shared */
private:
SMnet & operator= (const SMnet &rvalue);
public:
/* Destructor.
If you want to destroy this instance without closing your sockets,
you have to call remove_socket on them first. */
~SMnet() {
unsigned i;
for (i = 0; i < numsockets; i++) {
(void) close(sockets[i].fd); // Ignore result.
}
delete [] sockets;
delete [] sockinfo;
delete [] my_network_hostname;
delete [] random_string;
}
/* Add a file/network socket to the set to be polled */
void
add_socket(int socket, short events, int addrfam, int socktype,
int protofam, const struct sockaddr *addr,
socklen_t addrlen) {
if (numsockets >= allocsockets) {
struct pollfd *sox;
int newalloc = allocsockets + 10;
sox = new struct pollfd[newalloc];
memcpy(sox, sockets, numsockets * sizeof(*sockets));
delete [] sockets;
sockets = sox;
allocsockets = newalloc;
struct extra_sockinfo *si;
si = new struct extra_sockinfo[newalloc];
memcpy(si, sockinfo, numsockets * sizeof(*sockinfo));
delete [] sockinfo;
sockinfo = si;
}
sockets[numsockets].fd = socket;
sockets[numsockets].events = events;
sockets[numsockets].revents = 0;
sockinfo[numsockets].addrfam = addrfam;
sockinfo[numsockets].socktype = socktype;
sockinfo[numsockets].protofam = protofam;
if (addrlen <= sizeof(sockinfo[numsockets].addr)) {
sockinfo[numsockets].addrlen = addrlen;
memcpy(&sockinfo[numsockets].addr, addr, addrlen);
} else {
sockinfo[numsockets].addrlen = 0;
}
numsockets++;
}
/* Remove socket */
void
remove_socket(int socket) {
nfds_t i, j;
// Walk down the array, squeezing out all entries with socket
// Note, there may be several; get rid of all.
for (i = 0, j = 0; i < numsockets; i++) {
if (i != j)
sockets[j] = sockets[i];
if (sockets[i].fd != socket)
j++;
}
numsockets = j;
// We never shrink the allocation; it's almost peanuts.
}
/* Change the event mask for socket so that we'll awaken when
* it's possible to write to the socket (or not).
*
* In normal use, we don't care about writes; writes are buffered
* and happen automatically. But if a write would ever block,
* then our caller need to ask to be awakened when that situation stops.
*/
bool
care_about_writes(int socket, bool icare) {
nfds_t i;
for (i = 0; i < numsockets; i++) {
if (sockets[i].fd == socket) {
if (icare)
sockets[i].events |= POLLOUT;
else
sockets[i].events &= ~POLLOUT;
return true;
}
}
return false;
}
// Poll (wait for I/O or a timeout).
// Timeout is in milliseconds; -1 for infinite.
int
poll_sockets(int mstimeout)
{
int i;
if (mstimeout<0) mstimeout=-1;
i = poll (sockets, numsockets, mstimeout);
return i;
}
/*
* Initialize short-message handling.
* Make one or more sockets and set up to listen on them.
* This function is ipv6-agnostic, and even almost UDP/TCP-agnostic.
*/
bool listen_on_port(std::string port);
/*
* Get the next datagram from any socket of interest.
* We use a system call to poll for up to mstimeout milliseconds.
* Result < 0: error
* Result == 0: timeout, or it's OK to write to a write socket now.
* Result > 0: size of the datagram received.
*/
int get_next_dgram (char *buffer, size_t buffsize, int mstimeout);
/*
* Send a datagram on a handy socket
* FIXME: Make the source host/port match the one in the SIP dgram!
*/
bool send_dgram(char *buffer, size_t buffsize, char *toaddr,
size_t toaddrsize);
/*
* Deliver a short_msg_pending to its destination, using
* the addresses in the message's request URI.
* Result is false if failed; true if we think we sent it.
* (Note that an ack should come back eventually -- we don't await it.)
*/
bool
deliver_msg_datagram(short_msg_pending *);
/*
* The global name of this host (facing the network).
*/
char *
myhostname();
/* Make printable IP address */
std::string
string_addr (struct addrinfo *myaddr, bool withport);
/* Make printable IP address */
std::string
string_addr (struct sockaddr *sa, socklen_t len, bool withport);
/* Parse printable IP address and port */
bool
parse_addr (const char *str, char *sockad, socklen_t maxlen, socklen_t *len);
/*
* Return a different random integer each time we are called.
* They are all guaranteed to be positive numbers.
*/
unsigned int
new_random_number();
/*
* A different random number each time it's called. Designed
* to be unique for a long time, within the hostname above.
* Should not repeat even if the program is stopped and started.
*/
char *
new_call_number();
};
}; // namespace SMqueue
#endif