853 lines · 17.7 KB · C
RawDownload
/* * ------------------------------------------------------- * Copyright (C) 2002-2007 Tommi Saviranta <wnd@iki.fi> *	(C) 2002 Lee Hardy <lee@leeh.co.uk> *	(C) 1998-2002 Sebastian Kienzl <zap@riot.org> * ------------------------------------------------------- * 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 General Public License for more details. */ #ifdef HAVE_CONFIG_H#include <config.h>#endif /* ifdef HAVE_CONFIG_H */ #include "irc.h"#include "common.h"#include "conntype.h"#include "llist.h"#include "perm.h" #include <fcntl.h>#include <errno.h>#include <netdb.h>#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <string.h>#include <unistd.h>#include <arpa/inet.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h> #if HAVE_STRINGS_H#include <strings.h>#endif /* Guess this needs to go somewhere */typedef unsigned short u_short; /* #define DEBUG */ #ifdef HAVE_HSTRERROR#ifndef HAVE_HSTRERROR_PROTOconst char *hstrerror(int err);#endif /* ifndef HAVE_HSTRERROR_PROTO */#endif /* ifdef HAVE_HSTRERROR */ /* va_copy */#ifndef va_copy#ifdef HAVE___VA_COPY#define va_copy __va_copy#else /* ifdef HAVE___VA_COPY *//* we may need "memcpy(&dest, &src, sizeof(va_list))" on some systems */#define va_copy(dest, src) ((dest) = (src))#endif /* ifdef else HAVE___VA_COPY */#endif /* ifndef va_copy */  #define HEAD	1#define TAIL	2 static void track_highest(void);static void track_add(int s);static void track_del(int s);static int irc_write_smart(connection_type *connection, int queue,		char *format, va_list va); struct hostent *hostinfo = NULL;#ifdef IPV6struct sockaddr_in6 addr;#elsestruct sockaddr_in addr;#endif const char *net_errstr; #define TRACK 512int track_socks[TRACK]; int highest_socket = 0; int		msgtimer;	/* Message timer... */llist_list	msg_queue;	/* Message queue */   static voidtrack_highest(void){	int	i;	highest_socket = 0;	for (i = 0; i < TRACK; i++) {		if (track_socks[i] > highest_socket) {			highest_socket = track_socks[i];		}	}} /* void track_highest(void) */   static voidtrack_add(int s){	int	i = 0;	while (track_socks[i] && i < TRACK) {		i++;	}	if (i < TRACK) {		track_socks[i] = s;	}	track_highest();} /* void track_add(int s) */   static voidtrack_del(int s){	int	i;	for (i = 0; i < TRACK; i++) {		if (track_socks[i] == s) {			track_socks[i] = 0;		}	}	track_highest();} /* void track_del(int s) */   /* * Creates a socket. * * Returns number of opened socket or -1 if something went wrong. */intsock_open(void){	int	i; #ifdef IPV6	if ((i = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) < 0)#else	if ((i = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)#endif	{		net_errstr = strerror(errno);		return -1;	}	track_add(i);	sock_setreuse(i);	/* local reuse by default */	return i;} /* int sock_open(void) */   intrawsock_close(int sock){	if (! sock) return 1; 	track_del(sock);	close(sock);	return 1;} /* int rawsock_close(int sock) */   intsock_close(connection_type *connection){	rawsock_close(connection->socket);	connection->socket = 0;	return 1;} /* int sock_close(connection_type *connection) */   intsock_setnonblock(int sock){	if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {		net_errstr = strerror(errno);		return 0;	} else {		return 1;	}} /* int sock_setnonblock(int sock) */   intsock_setblock(int sock){	int	flags; 	flags = fcntl(sock, F_GETFL, 0);	if (flags == -1) {		net_errstr = strerror(errno);		return 0;	} 	flags &= ~O_NONBLOCK; 	if (fcntl(sock, F_SETFL, flags) < 0) {		net_errstr = strerror(errno);		return 0;	} 	return 1;} /* int sock_setblock(int sock) */   intsock_setreuse(int sock){	int	i = 1; 	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &i,				sizeof(i)) < 0) {		net_errstr = strerror(errno);		return 0;	} else {		return 1;	}} /* int sock_setreuse(int sock) */   struct hostent *name_lookup(char *host){#ifdef IPV6	hostinfo = gethostbyname2(host, AF_INET6);	if (hostinfo != NULL) {		return hostinfo;	}#else /* IPV6 */	hostinfo = gethostbyname(host);	if (hostinfo != NULL) {		return hostinfo;	}#endif /* IPV6 */ 	/* TODO: hstrerror is obsolete */#ifdef HAVE_HSTRERROR	net_errstr = (const char *) hstrerror(h_errno);#else	net_errstr = "unable to resolve";#endif	return NULL;} /* struct hostent *name_lookup(char *host) */   #ifdef IPV6intsock_bind(int sock, char *bindhost, int port){	/* We'd better cast &addr to void * to keep Digital-UNIX happy. */	memset((void *) &addr, 0, sizeof(struct sockaddr_in6)); 	addr.sin6_addr = in6addr_any;	addr.sin6_family = AF_INET6; 	if (bindhost) {		if (! name_lookup(bindhost)) {			return 0;		} 		memcpy((char *) &addr.sin6_addr, hostinfo->h_addr,				hostinfo->h_length);		addr.sin6_family = hostinfo->h_addrtype;	} 	addr.sin6_port = htons((u_short)port); 	if (bind(sock, (struct sockaddr *) &addr,				sizeof(struct sockaddr_in6)) < 0) {		net_errstr = strerror(errno);		return 0;	} 	return 1;} /* int sock_bind(int sock, char *bindhost, int port) */   intsock_bindlookedup(int sock, int port){	/* We'd better cast &addr to void * to keep Digital-UNIX happy. */	memset((void *) &addr, 0, sizeof(struct sockaddr_in6)); 	addr.sin6_addr = in6addr_any;	addr.sin6_family = AF_INET6; 	if (hostinfo) {		memcpy((char *) &addr.sin6_addr, hostinfo->h_addr,				hostinfo->h_length);		addr.sin6_family = hostinfo->h_addrtype;	} 	addr.sin6_port = htons((u_short)port); 	if (bind(sock, (struct sockaddr *)&addr,				sizeof(struct sockaddr_in6)) < 0) {		net_errstr = strerror(errno);		return 0;	} 	return 1;} /* int sock_bindlookedup(int sock, int port) */ #else intsock_bind(int sock, char *bindhost, int port){	/* We'd better cast &addr to void * to keep Digital-UNIX happy. */	memset((void *) &addr, 0, sizeof(struct sockaddr_in)); 	addr.sin_addr.s_addr = INADDR_ANY;	addr.sin_family = AF_INET; 	if (bindhost) {		if (name_lookup(bindhost) == NULL) {			return 0;		} 		memcpy((char *) &addr.sin_addr, hostinfo->h_addr,				hostinfo->h_length);		addr.sin_family = hostinfo->h_addrtype;	} 	addr.sin_port = htons((u_short) port); 	if (bind(sock, (struct sockaddr *) &addr,				sizeof(struct sockaddr)) < 0) {		net_errstr = strerror(errno);		return 0;	} 	return 1;} /* int sock_bind(int sock, char *bindhost, int port) */   intsock_bindlookedup(int sock, int port){	/* We'd better cast &addr to void * to keep Digital-UNIX happy. */	memset((void *) &addr, 0, sizeof(struct sockaddr_in)); 	addr.sin_addr.s_addr = INADDR_ANY;	addr.sin_family = AF_INET; 	if (hostinfo) {		memcpy((char *) &addr.sin_addr, hostinfo->h_addr,				hostinfo->h_length);		addr.sin_family = hostinfo->h_addrtype;	} 	addr.sin_port = htons((u_short) port); 	if (bind(sock, (struct sockaddr *) &addr,				sizeof(struct sockaddr)) < 0) {		net_errstr = strerror(errno);		return 0;	} 	return 1;} /* int sock_bindlookedup(int sock, int port) */ #endif   intsock_listen(int sock){	if (! sock_setnonblock(sock)) {		return 0;	} 	if (listen(sock, QUEUESIZE) < 0) {		net_errstr = strerror(errno);		return 0;	} 	return 1;} /* int sock_listen(int sock) */   /* * Accept socket. Return socket. * * If checkperm is non-zero, a check is made to be sure connecting IP is allowed * to establish a connection with us. If connection is unauthorized, connection * will be closed and function returns -1. */typedef int socklen_t; intsock_accept(int sock, char **s, int checkperm){	socklen_t	temp;	int		store;#ifdef IPV6	char		ip[40];	char		ipv6[512];#else	char		*ip;#endif	int		perm; #ifdef IPV6	temp = sizeof(struct sockaddr_in6);#else	temp = sizeof(struct sockaddr_in);#endif	if ((store = accept(sock, (struct sockaddr *) &addr, &temp)) < 0) {		net_errstr = strerror(errno);		return 0;	} #ifdef IPV6	inet_ntop(AF_INET6, (char *) &addr.sin6_addr, ip,			sizeof(addr.sin6_addr));#else	ip = inet_ntoa(addr.sin_addr);#endif	perm = is_perm(&connhostlist, ip); #ifdef IPV6	if (! getnameinfo((struct sockaddr *) &addr, sizeof(addr), ipv6,				sizeof(ipv6), 0, 0, 0)) {		*s = xstrdup(ipv6);		perm |= is_perm(&connhostlist, *s);	} else {		*s = xstrdup(ip);	} #else	hostinfo = gethostbyaddr((char *) &addr.sin_addr.s_addr,			sizeof(struct in_addr), AF_INET); 	if (hostinfo) {		*s = xstrdup(hostinfo->h_name);		perm |= is_perm(&connhostlist, *s);	} else {		*s = xstrdup(ip);	}#endif 	if (! checkperm || perm) {		track_add(store);		return store;	} else {		close(store);		return -1;	}} /* int sock_accept(int sock, char **s, int checkperm) */   /* * Send data to all connected clients. */intirc_mwrite(clientlist_type *clients, char *format, ...){	llist_node *client;	va_list va;	int ret; 	if (clients->connected == 0) {		return 0;	} 	ret = 0;	va_start(va, format);	for (client = clients->clients->head; client != NULL;			client = client->next) {		va_list cva;		/*		 * Having '"%s", buffer' instead of plain 'buffer' is essential		 * because we don't want our string processed any further by		 * va.		 */

Lines 1–500 of 853.