#include	<stdio.h>
#include	<sys/types.h>
#include	"clibrary.h"
#include	<errno.h>
#include	<sys/socket.h>
#include	<netinet/in.h>
#include	<netdb.h>
#include	"logging.h"

#ifdef NEED_BZERO_ETC
#include <fcntl.h>
void
bzero(b, length)
    char *b;
    int length;
{
    while (--length >= 0)
        *b++ = '\0';
}
void
bcopy(b1, b2, length)
    char *b1;
    char *b2;
    int length;
{
    while (--length >= 0)
        *b2++ = *b1++;
}
#endif

int create_udp_socket(int port)
{
	int s;
	struct sockaddr_in sin;

	sin.sin_port = htons(port);
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = INADDR_ANY;

	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		syslog(L_ERROR, "create_udp_socket: socket: %m");
		return(-1);
	}
	if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
		syslog(L_ERROR, "create_udp_socket: bind: %m");
		return(-1);
	}
	return(s);
}





int make_udp_sockaddr(struct sockaddr_in *addr, char *ascii)
{
        struct hostent *host;
        int dots = 0;
        int numeric = 0;
	char *str, *colon, *lastdot, *ptr;

	if (! (str = malloc(strlen(ascii) + 1))) {
		syslog(L_ERROR, "make_udp_sockaddr: malloc: %m");
		return(-1);
        }
	strcpy(str, ascii);
	colon = strrchr(str, ':');
	lastdot = strrchr(str, '.');

        addr->sin_family = AF_INET;

        /* Count the number of dots in the address. */
        for (ptr = str; *ptr; ptr++) {
                if (*ptr == '.') {
                        dots++;
                }
        }

        /* Check if it seems to be numeric. */
        numeric = isdigit(*str);

        /* If numeric and four dots, we have a.b.c.d.6000 */
        if (numeric && dots == 4) {
                *lastdot = '\0';
                addr->sin_port = htons(atoi(lastdot + 1));
        }
        /* If nonnumeric, check if the last part is a port */
        if (! numeric && lastdot && isdigit(*(lastdot + 1))) {
                *lastdot = '\0';
                addr->sin_port = htons(atoi(lastdot + 1));
        }
        /* Now do we have a numeric address */
        if (numeric) {
                addr->sin_addr.s_addr = inet_addr(str);
                free(str);
                return(0);
        }
        /* Or a name */
        if (! (host = gethostbyname(str))) {
                free(str);
                syslog(L_ERROR, "make_udp_sockaddr: gethostbyname: %m");
		return(-1);
        }
        bcopy(host->h_addr_list[0], (char *)&addr->sin_addr.s_addr, sizeof(addr->sin_addr.s_addr));
        free(str);
        return(0);
}





int connect_udp_socket(int s, char *address, int port)
{
	struct sockaddr_in sin;

	bzero(&sin, sizeof(sin));
	sin.sin_port = htons(port);
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = INADDR_ANY;

	if (make_udp_sockaddr(&sin, address) < 0) {
		return(-1);
	}
	if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
		syslog(L_ERROR, "connect_udp_socket: connect: %m");
		return(-1);
	}
	return(0);
}





int write_udp(int s, char *buf, int len)
{
	int rval;

	if ((rval = send(s, buf, len, 0x0)) < 0) {
		syslog(L_ERROR, "write_udp: send: %m");
		return(-1);
	}
	return(rval);
}





int read_udp(int s, char *buf, int len)
{
	int rval;

	if ((rval = recv(s, buf, len, 0x0)) < 0) {
		syslog(L_ERROR, "read_udp: recv: %m");
		return(-1);
	}
	return(rval);
}
