/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "networklib.h"
int string2int(const char * str) {
/* -----------------------------------------------------------------------------
* Convert a string to int
*
* @param const char *, the given string
* @return int -1 if the given string do not represent an integer
* -------------------------------------------------------------------------- */
const char *pts = str;
int result_int = 0;
while(*pts != '\0') {
if ((*pts >= 48) && (*pts <= 57))
result_int = result_int*10 + (*pts - 48);
else
return -1;
pts++;
}
return result_int;
}
int read_buffer(int fd, void * buffer, int count) {
/* -----------------------------------------------------------------------------
* Read to buffer
*
* @param int, the file descriptor to read on
* @param void *, the buffer where to store
* @param int, the max number of character to read
* @return int the number of character read or -1 if an error occurss
* -------------------------------------------------------------------------- */
int status = 0, n;
while(status < count) {
n = read(fd, (void *)&((char *)buffer)[status], count - status);
if (n < 1) {
/* end-of-file (0) or an error occurs (-1) */
if (status == 0)
return n;
else
return status;
}
status += n;
}
return status;
}
int write_buffer(int fd, const void * buffer, int count) {
/* -----------------------------------------------------------------------------
* Write buffer to a file descriptor
*
* @param int, the file descriptor to write on
* @param void *, the buffer that must be written to file descriptor
* @param int, the max number of character to read
* @return int the number of character written or -1 if an error occurs
* -------------------------------------------------------------------------- */
int status = 0, n;
while(status < count) {
n = write(fd, (const void *)&((char *)buffer)[status], count - status);
if (n < 1) {
/* an error occurs (-1) */
if (status == 0)
return n;
else
return status;
}
status += n;
}
return status;
}
int xsend(int socket, int flags, const char * str, ...) {
/* -----------------------------------------------------------------------------
* Write buffer to a socket
*
* @param int, the socket file descriptor to write on
* @param int, flags that are passed to send() function
* @param const char *, printf format
* @param ...
* @return int the number of character written or -1 if an error occurs
* -------------------------------------------------------------------------- */
va_list args;
char *result = NULL;
int retour;
va_start(args, str);
vasprintf(&result, str, args);
va_end(args);
if (result != NULL) {
retour = send(socket, result, strlen(result), flags);
free(result);
switch(errno) {
case EBADF:
case ENOTSOCK:
case EFAULT:
case EMSGSIZE:
case EAGAIN:
case ENOBUFS:
case EINTR:
case ENOMEM:
case EINVAL:
case EPIPE:
return -1;
break;
default:
return retour;
break;
}
}
return -1;
}
int readline(int fd, char * buffer, int maxlen) {
/* -----------------------------------------------------------------------------
* Read line to buffer
*
* @param int, the file descriptor to read on
* @param char *, the buffer where to store
* @param int, the max number of character to read
* @return int the number of character read
* -------------------------------------------------------------------------- */
int count = 0, status;
while(count < maxlen) {
/* Read one character */
if ((status = read_buffer(fd, (void *)&((char *)buffer)[count], 1)) <= 0) {
/* Nothing to read */
return count;
}
else {
if (buffer[count] == '\n'){
buffer[count + 1] = '\0';
return count + 1;
}
}
count += status;
}
buffer[count] = 0;
return 0;
}
int copy(int fd_in, int fd_out, unsigned long maxlen) {
/* -----------------------------------------------------------------------------
* Copy data to one file descriptor to another
*
* @param int, the file descriptor to read on
* @param int, the file descriptor to write on
* @param int, the max number of character to read
* @return int
* -------------------------------------------------------------------------- */
char buffer[BUF_SIZE];
int data_in;
unsigned long remaining;
remaining = maxlen;
while ((remaining != 0) || (maxlen == 0)) {
if ((remaining == 0) || (BUF_SIZE < remaining)) {
data_in = read(fd_in, buffer, BUF_SIZE);
}
else {
data_in = read(fd_in, buffer, remaining);
}
if (data_in < 1) return data_in;
write_buffer(fd_out, buffer, data_in);
if (maxlen != 0) remaining -= data_in;
}
return 1;
}
char * getfqdn(const char * host) {
/* -----------------------------------------------------------------------------
* Get full hostname by IP address or a name
*
* @param const char *, the IP address in human readable format or a host
* @return char *
* -------------------------------------------------------------------------- */
struct hostent *host_info;
u_long ip_addr;
static char fqdn[200];
if (isipv4(host)) {
ip_addr = inet_addr(host);
host_info = gethostbyaddr((char *)&ip_addr, sizeof(struct in_addr), AF_INET);
}
else {
host_info = gethostbyname(host);
}
if (!host_info) {
logmsg(LOG_ERR, "%s (%d)", strerror(errno), errno);
return (char *)NULL;
}
if (host_info->h_aliases[0]) {
strncpy(fqdn, host_info->h_aliases[0], sizeof(fqdn));
}
else {
strncpy(fqdn, host_info->h_name, sizeof(fqdn));
}
return fqdn;
}
char * getmyfqdn() {
/* -----------------------------------------------------------------------------
* Get full hostname of the current machine
*
* @return char *
* -------------------------------------------------------------------------- */
char hostname[200];
gethostname(hostname, sizeof(hostname));
return getfqdn(hostname);
}
char *get_host(const char *host) {
/* -----------------------------------------------------------------------------
* Get full hostname by IP address or a name
*
* @param const char *, the IP address in human readable format or a host
* @return char *,
* if they are alternate names for the given parameters
* they will be returned with a \n separator
* -------------------------------------------------------------------------- */
struct hostent *host_info;
static char hosts[300];
u_long ip_addr;
char **aliases;
if (isipv4(host)) {
ip_addr = inet_addr(host);
host_info = gethostbyaddr((char *)&ip_addr, sizeof(struct in_addr), AF_INET);
}
else {
host_info = gethostbyname(host);
}
if (!host_info) {
logmsg(LOG_ERR, "%s (%d)", hstrerror(h_errno), h_errno);
return (char *)NULL;
}
snprintf(hosts, sizeof(hosts), "%s", host_info->h_name);
for (aliases = host_info->h_aliases; *aliases != 0; aliases++) {
strlcat(hosts, "\n", sizeof(hosts));
strlcat(hosts, *aliases, sizeof(hosts));
}
return hosts;
}
char *get_ip(const char *host) {
/* -----------------------------------------------------------------------------
* Get IP addressby host
*
* @param const char *, the hostname
* @return char *
* if they are alternate IP addresses for the given parameters
* they will be returned with a \n separator
* -------------------------------------------------------------------------- */
struct hostent *host_info;
static char ip[300];
u_long ip_addr;
struct in_addr in;
char **ip_list;
if (isipv4(host)) {
ip_addr = inet_addr(host);
host_info = gethostbyaddr((char *)&ip_addr, sizeof(struct in_addr), AF_INET);
}
else {
host_info = gethostbyname(host);
}
if (!host_info) {
logmsg(LOG_ERR, "%s (%d)", hstrerror(h_errno), h_errno);
return (char *)NULL;
}
*ip = '\0';
for (ip_list = host_info->h_addr_list; *ip_list != 0; ip_list++) {
memcpy(&in.s_addr, *ip_list, sizeof (in.s_addr));
strlcat(ip, "\n", sizeof(ip));
strlcat(ip, inet_ntoa(in), sizeof(ip));
}
return ip+1;
}
int isipv4(const char *ip) {
/* -----------------------------------------------------------------------------
* Check if the given IP is a valid IPV4 address in human readable format
* e.g : 127.0.0.1
*
* @param const char *, the IP to check
* @return int
* -------------------------------------------------------------------------- */
const int dots = 3;
const char *pts = ip;
int number = 0, count_dots = 0;
while(*pts != '\0') {
if ((*pts >= 48) && (*pts <= 57)) {
number = number*10 + (*pts - 48);
}
else if (*pts == '.') {
if ((number >= 0) && (number <= 255)) {
number = 0;
count_dots++;
}
else {
return 0;
}
}
else {
return 0;
}
pts++;
}
if ((count_dots == dots) && (number >= 0) && (number <= 255))
return 1;
else
return 0;
}
unsigned int sockaddr_localinfo(int sockid, struct sockaddr_in * socketaddr) {
/* -----------------------------------------------------------------------------
* Get local peer info from a socket file descriptor
*
* @param int, the socket file descriptor
* @param struct sockaddr_in *, the struct info to fill
* @return int
* -------------------------------------------------------------------------- */
socklen_t size;
size = sizeof(struct sockaddr_in);
if (getsockname(sockid, (struct sockaddr *)socketaddr, &size) != 0) {
logmsg(LOG_ERR, "%s (%d)", strerror(errno), errno);
return 0;
}
return 1;
}
short getlocalport(int sockid) {
/* -----------------------------------------------------------------------------
* Get local port info from a socket file descriptor
*
* @param int, the socket file descriptor
* @return short, the local port or -1
* -------------------------------------------------------------------------- */
struct sockaddr_in socketaddr;
if (sockaddr_localinfo(sockid, &socketaddr)) {
return ntohs(socketaddr.sin_port);
}
return -1;
}
char * getlocaladdr(int sockid) {
/* -----------------------------------------------------------------------------
* Get local IP address info from a socket file descriptor
*
* @param int, the socket file descriptor
* @return char *
* -------------------------------------------------------------------------- */
struct sockaddr_in socketaddr;
if (sockaddr_localinfo(sockid, &socketaddr)) {
return inet_ntoa(socketaddr.sin_addr);
}
return NULL;
}
unsigned int sockaddr_peerinfo(int sockid, struct sockaddr_in * socketaddr) {
/* -----------------------------------------------------------------------------
* Get Remote peer info from a socket file descriptor
*
* @param int, the socket file descriptor
* @param struct sockaddr_in *, the struct info to fill
* @return int
* -------------------------------------------------------------------------- */
socklen_t size;
size = sizeof(struct sockaddr_in);
if (getpeername(sockid, (struct sockaddr *)socketaddr, &size) != 0) {
logmsg(LOG_ERR, "%s (%d)", strerror(errno), errno);
return 0;
}
return 1;
}
short getforeignport(int sockid) {
/* -----------------------------------------------------------------------------
* Get remote port info from a socket file descriptor
*
* @param int, the socket file descriptor
* @return short, the local port or -1
* -------------------------------------------------------------------------- */
struct sockaddr_in socketaddr;
if (sockaddr_peerinfo(sockid, &socketaddr)) {
return ntohs(socketaddr.sin_port);
}
return -1;
}
char *getforeignaddr(int sockid) {
/* -----------------------------------------------------------------------------
* Get remote IP address info from a socket file descriptor
*
* @param int, the socket file descriptor
* @return char *
* -------------------------------------------------------------------------- */
struct sockaddr_in socketaddr;
if (sockaddr_peerinfo(sockid, &socketaddr)) {
return inet_ntoa(socketaddr.sin_addr);
}
return NULL;
}
void socketaddr_init(struct sockaddr_in * socketaddr) {
/* -----------------------------------------------------------------------------
* Init a sockaddr_in struct
*
* @param struct sockaddr_in
* -------------------------------------------------------------------------- */
memset(socketaddr, 0, sizeof(struct sockaddr_in));
socketaddr->sin_family = AF_INET;
}
int socketaddr_service(struct sockaddr_in * socketaddr, const char * service, const char * proto) {
/* -----------------------------------------------------------------------------
* Init a sockaddr_in struct to the given service and protocol
*
* @param struct sockaddr_in
* @param const char *, name service or port number
* @param const char *, name protocol
* @return int
* -------------------------------------------------------------------------- */
struct servent * service_info;
int port;
if (strcmp(service, "0") == 0) {
socketaddr->sin_port = 0;
}
else {
service_info = getservbyname(service, proto);
if (service_info) {
socketaddr->sin_port = service_info->s_port;
}
else {
/* service is a port number */
port = string2int(service);
if (port != -1) {
socketaddr->sin_port = htons((u_short)port);
}
else {
logmsg(LOG_ERR, "%s (%d)", strerror(errno), errno);
return 0;
}
}
}
return 1;
}
int socketaddr_host(struct sockaddr_in * socketaddr, const char * host) {
/* -----------------------------------------------------------------------------
* Init a sockaddr_in struct to the given host
*
* @param struct sockaddr_in
* @param const char *, hostname or IP address
* @return int
* -------------------------------------------------------------------------- */
struct hostent * host_info;
host_info = gethostbyname(host);
if (!host_info) {
logmsg(LOG_ERR, "%s (%d)\n", strerror(errno), errno);
return 0;
}
memcpy(&socketaddr->sin_addr, host_info->h_addr, host_info->h_length);
return 1;
}
int resolveproto(const char * proto) {
/* -----------------------------------------------------------------------------
* Resolve protocol by name
*
* @param const char *, name protocol like "tcp", "udp"
* @return int or -1
* -------------------------------------------------------------------------- */
struct protoent * proto_info;
proto_info = getprotobyname(proto);
if (!proto_info) {
logmsg(LOG_ERR, "%s (%d)\n", strerror(errno), errno);
return -1;
}
return proto_info->p_proto;
}
int prototype(const char * proto) {
/* -----------------------------------------------------------------------------
* Resolve IPV4 protocol by name
*
* @param const char *, name protocol like "tcp", "udp"
* @return int or -1
* -------------------------------------------------------------------------- */
if (strcmp(proto, "tcp") == 0) return SOCK_STREAM;
if (strcmp(proto, "udp") == 0) return SOCK_DGRAM;
logmsg(LOG_ERR, "Unknown protocol %s", proto);
return -1;
}
#ifdef USE_UNIX_SOCKET
int create_unix_socket (const char *filename) {
/* -----------------------------------------------------------------------------
* Create an Unix socket
*
* @param const char *, socket file name
* @return int, the server socket file descriptor or -1
* -------------------------------------------------------------------------- */
struct sockaddr_un socketaddr;
int sockid;
int trueval = TRUE;
size_t size;
sockid = socket (PF_UNIX, SOCK_STREAM, 0);
if (sockid < 0) {
logmsg(LOG_ERR, "%s (%d) : Create Unix Socket error", strerror(errno), errno);
return -1;
}
socketaddr.sun_family = AF_UNIX;
strlcpy(socketaddr.sun_path, filename, sizeof(socketaddr.sun_path));
#if defined __Linux__
size = offsetof(struct sockaddr_un, sun_path)
+ strlen (socketaddr.sun_path) + 1;
#endif
#if defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__
socketaddr.sun_len = sizeof(socketaddr.sun_len)
+ sizeof(socketaddr.sun_family)
+ strlen (socketaddr.sun_path) + 1;
size = socketaddr.sun_len;
#endif
setsockopt(sockid, SOL_SOCKET, SO_REUSEADDR, &trueval, sizeof(trueval));
if (!access(socketaddr.sun_path, F_OK))
unlink(socketaddr.sun_path);
if (bind (sockid, (struct sockaddr *) &socketaddr, size) < 0) {
logmsg(LOG_ERR, "%s (%d) : Bind Unix Socket error", strerror(errno), errno);
return -1;
}
if (listen(sockid, 5) < 0) {
logmsg(LOG_ERR, "%s (%d) : Listen Unix Socket error", strerror(errno), errno);
return -1;
}
return sockid;
}
#endif
int open_unix_fd(const char *filename) {
/* -----------------------------------------------------------------------------
* Connect to an Unix socket
*
* @param const char *, the socket file name
* @return int, the client socket file descriptor
* -------------------------------------------------------------------------- */
struct sockaddr_un socketaddr;
int sockid;
socketaddr.sun_family = AF_UNIX;
strlcpy(socketaddr.sun_path, filename, sizeof(socketaddr.sun_path));
sockid = socket(PF_UNIX, SOCK_STREAM, 0);
if (sockid == -1) return -1;
if (connect(sockid, (struct sockaddr *)&socketaddr, sizeof(socketaddr)) < 0) {
logmsg(LOG_ERR, "%s (%d)\n", strerror(errno), errno);
return -1;
}
return sockid;
}
int client_connect(const char * host, const char * port, const char * proto) {
/* -----------------------------------------------------------------------------
* Connect to a hostname, with the given port and protocol
*
* @param const char *, hostname
* @param const char *, port number or name service
* @param const char *, name protocol
* @return int, the client socket descriptor or -1
* -------------------------------------------------------------------------- */
struct sockaddr_in socketaddr;
int sockid;
socketaddr_init(&socketaddr);
socketaddr_service(&socketaddr, port, proto);
socketaddr_host(&socketaddr, host);
sockid = socket(PF_INET, prototype(proto), resolveproto(proto));
if (sockid < 0) {
logmsg(LOG_ERR, "%s (%d) : Create Socket error", strerror(errno), errno);
return -1;
}
if (connect(sockid, (struct sockaddr *)&socketaddr, sizeof(socketaddr)) < 0) {
logmsg(LOG_ERR, "%s (%d) : Connect Socket error", strerror(errno), errno);
return -1;
}
return sockid;
}
int server_init(const char * port, const char * proto) {
/* -----------------------------------------------------------------------------
* Init a server with the given port and protocol
*
* @param const char *, port number or name service
* @param const char *, name protocol
* @return int, the server socket descriptor or -1
* -------------------------------------------------------------------------- */
struct sockaddr_in socketaddr;
int mastersock;
int trueval = TRUE;
socketaddr_init(&socketaddr);
socketaddr.sin_addr.s_addr = INADDR_ANY;
if (port != NULL)
socketaddr_service(&socketaddr, port, proto);
mastersock = socket(PF_INET, prototype(proto), resolveproto(proto));
if (mastersock < 0) {
logmsg(LOG_ERR, "%s (%d) : Create Server Socket error", strerror(errno), errno);
return -1;
}
setsockopt(mastersock, SOL_SOCKET, SO_REUSEADDR, &trueval, sizeof(trueval));
if (bind(mastersock, (struct sockaddr *) &socketaddr, sizeof(socketaddr)) < 0) {
logmsg(LOG_ERR, "%s (%d) : Bind Socket error", strerror(errno), errno);
return -1;
}
if (prototype(proto) == SOCK_STREAM) {
if (listen(mastersock, 5) < 0) {
logmsg(LOG_ERR, "%s (%d) : Listen Socket error", strerror(errno), errno);
return -1;
}
}
return mastersock;
}
syntax highlighted by Code2HTML, v. 0.9.1