#include "channel.h"
#include "class.h"
#include "hash.h"
+#include "ircd_alloc.h"
#include "ircd_log.h"
#include "ircd_features.h"
#include "ircd_osdep.h"
#include "version.h"
#include <arpa/inet.h>
-#include <arpa/nameser.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
-#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
#endif /* USE_POLL */
-#ifndef INADDR_NONE
-#define INADDR_NONE 0xffffffff
-#endif
-
struct Client* LocalClientArray[MAXCONNECTIONS];
int HighestFd = -1;
-struct sockaddr_in VirtualHost;
+struct irc_sockaddr VirtualHost;
static char readbuf[SERVER_TCP_WINDOW];
/*
* a non-null pointer, otherwise reply will be null.
* if successful start the connection, otherwise notify opers
*/
-static void connect_dns_callback(void* vptr, struct DNSReply* reply)
+static void connect_dns_callback(void* vptr, struct DNSReply* hp)
{
struct ConfItem* aconf = (struct ConfItem*) vptr;
+ assert(aconf);
aconf->dns_pending = 0;
- if (reply) {
- memcpy(&aconf->ipnum, reply->hp->h_addr, sizeof(struct in_addr));
- connect_server(aconf, 0, reply);
+ if (hp) {
+ memcpy(&aconf->address, &hp->addr, sizeof(aconf->address));
+ MyFree(hp);
+ connect_server(aconf, 0);
}
else
sendto_opmask_butone(0, SNO_OLDSNO, "Connect to %s failed: host lookup",
void close_connections(int close_stderr)
{
int i;
-#if 0
close(0);
close(1);
if (close_stderr)
close(2);
-#endif
for (i = 3; i < MAXCONNECTIONS; ++i)
close(i);
}
*/
static int connect_inet(struct ConfItem* aconf, struct Client* cptr)
{
- static struct sockaddr_in sin;
+ const struct irc_sockaddr *local;
IOResult result;
assert(0 != aconf);
assert(0 != cptr);
* Might as well get sockhost from here, the connection is attempted
* with it so if it fails its useless.
*/
- cli_fd(cptr) = socket(AF_INET, SOCK_STREAM, 0);
- if (-1 == cli_fd(cptr)) {
- cli_error(cptr) = errno;
- report_error(SOCKET_ERROR_MSG, cli_name(cptr), errno);
- return 0;
- }
- if (cli_fd(cptr) >= MAXCLIENTS) {
- report_error(CONNLIMIT_ERROR_MSG, cli_name(cptr), 0);
- close(cli_fd(cptr));
- cli_fd(cptr) = -1;
- return 0;
- }
- /*
- * Bind to a local IP# (with unknown port - let unix decide) so
- * we have some chance of knowing the IP# that gets used for a host
- * with more than one IP#.
- *
- * No we don't bind it, not all OS's can handle connecting with
- * an already bound socket, different ip# might occur anyway
- * leading to a freezing select() on this side for some time.
- * I had this on my Linux 1.1.88 --Run
- */
-
- /*
- * No, we do bind it if we have virtual host support. If we don't
- * explicitly bind it, it will default to IN_ADDR_ANY and we lose
- * due to the other server not allowing our base IP --smg
- */
- if (feature_bool(FEAT_VIRTUAL_HOST) &&
- bind(cli_fd(cptr), (struct sockaddr*) &VirtualHost,
- sizeof(VirtualHost))) {
- report_error(BIND_ERROR_MSG, cli_name(cptr), errno);
- close(cli_fd(cptr));
- cli_fd(cptr) = -1;
+ if (irc_in_addr_valid(&aconf->origin.addr))
+ local = &aconf->origin;
+ else
+ local = &VirtualHost;
+ cli_fd(cptr) = os_socket(local, SOCK_STREAM, cli_name(cptr));
+ if (cli_fd(cptr) < 0)
return 0;
- }
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = aconf->ipnum.s_addr;
- sin.sin_port = htons(aconf->port);
/*
* save connection info in client
*/
- (cli_ip(cptr)).s_addr = aconf->ipnum.s_addr;
- cli_port(cptr) = aconf->port;
- ircd_ntoa_r(cli_sock_ip(cptr), (const char*) &(cli_ip(cptr)));
+ memcpy(&cli_ip(cptr), &aconf->address.addr, sizeof(cli_ip(cptr)));
+ cli_port(cptr) = aconf->address.port;
+ ircd_ntoa_r(cli_sock_ip(cptr), &cli_ip(cptr));
/*
* we want a big buffer for server connections
*/
- if (!os_set_sockbufs(cli_fd(cptr), SERVER_TCP_WINDOW)) {
+ if (!os_set_sockbufs(cli_fd(cptr), feature_int(FEAT_SOCKSENDBUF), feature_int(FEAT_SOCKRECVBUF))) {
cli_error(cptr) = errno;
report_error(SETBUFS_ERROR_MSG, cli_name(cptr), errno);
close(cli_fd(cptr));
cli_fd(cptr) = -1;
return 0;
}
- /*
- * ALWAYS set sockets non-blocking
- */
- if (!os_set_nonblocking(cli_fd(cptr))) {
- cli_error(cptr) = errno;
- report_error(NONB_ERROR_MSG, cli_name(cptr), errno);
- close(cli_fd(cptr));
- cli_fd(cptr) = -1;
- return 0;
- }
- if ((result = os_connect_nonb(cli_fd(cptr), &sin)) == IO_FAILURE) {
+ if ((result = os_connect_nonb(cli_fd(cptr), &aconf->address)) == IO_FAILURE) {
cli_error(cptr) = errno;
report_error(CONNECT_ERROR_MSG, cli_name(cptr), errno);
close(cli_fd(cptr));
switch (os_sendv_nonb(cli_fd(cptr), buf, &bytes_count, &bytes_written)) {
case IO_SUCCESS:
- cli_flags(cptr) &= ~FLAGS_BLOCKED;
+ ClrFlag(cptr, FLAG_BLOCKED);
cli_sendB(cptr) += bytes_written;
cli_sendB(&me) += bytes_written;
* say it was blocked
*/
if (bytes_written < bytes_count)
- cli_flags(cptr) |= FLAGS_BLOCKED;
+ SetFlag(cptr, FLAG_BLOCKED);
break;
case IO_BLOCKED:
- cli_flags(cptr) |= FLAGS_BLOCKED;
+ SetFlag(cptr, FLAG_BLOCKED);
break;
case IO_FAILURE:
cli_error(cptr) = errno;
- cli_flags(cptr) |= FLAGS_DEADSOCKET;
+ SetFlag(cptr, FLAG_DEADSOCKET);
break;
}
return bytes_written;
assert(MyConnect(cptr));
if (cli_dns_reply(cptr)) {
- assert(0 < cli_dns_reply(cptr)->ref_count);
- --(cli_dns_reply(cptr))->ref_count;
+ MyFree(cli_dns_reply(cptr)->h_name);
+ MyFree(cli_dns_reply(cptr));
cli_dns_reply(cptr) = 0;
}
}
* Make us timeout after twice the timeout for DNS look ups
*/
cli_lasttime(cptr) = CurrentTime;
- cli_flags(cptr) |= FLAGS_PINGSENT;
+ SetFlag(cptr, FLAG_PINGSENT);
sendrawto_one(cptr, MSG_SERVER " %s 1 %Tu %Tu J%s %s%s +%s :%s",
cli_name(&me), cli_serv(&me)->timestamp, newts,
socket_del(&(cli_socket(cptr))); /* queue a socket delete */
cli_fd(cptr) = -1;
}
- cli_flags(cptr) |= FLAGS_DEADSOCKET;
+ SetFlag(cptr, FLAG_DEADSOCKET);
MsgQClear(&(cli_sendQ(cptr)));
client_drop_sendq(cli_connect(cptr));
* passed off to the auth handler for dns and ident queries.
*--------------------------------------------------------------------------*/
void add_connection(struct Listener* listener, int fd) {
- struct sockaddr_in addr;
+ struct irc_sockaddr addr;
struct Client *new_client;
time_t next_target = 0;
/* 12345678901234567890123456789012345679012345678901234567890123456 */
const char* const register_message =
"ERROR :Unable to complete your registration\r\n";
-
+
assert(0 != listener);
-
/*
* Removed preliminary access check. Full check is performed in m_server and
* m_user instead. Also connection time out help to get rid of unwanted
- * connections.
+ * connections.
*/
if (!os_get_peername(fd, &addr) || !os_set_nonblocking(fd)) {
++ServerStats->is_ref;
*
* If they're throttled, murder them, but tell them why first.
*/
- if (!IPcheck_local_connect(addr.sin_addr, &next_target) && !listener->server)
+ if (!IPcheck_local_connect(&addr.addr, &next_target) && !listener->server)
{
++ServerStats->is_ref;
write(fd, throttle_message, strlen(throttle_message));
return;
}
- new_client = make_client(0, ((listener->server) ?
+ new_client = make_client(0, ((listener->server) ?
STAT_UNKNOWN_SERVER : STAT_UNKNOWN_USER));
/*
* Copy ascii address to 'sockhost' just in case. Then we have something
- * valid to put into error messages...
+ * valid to put into error messages...
*/
SetIPChecked(new_client);
- ircd_ntoa_r(cli_sock_ip(new_client), (const char*) &addr.sin_addr);
+ ircd_ntoa_r(cli_sock_ip(new_client), &addr.addr);
strcpy(cli_sockhost(new_client), cli_sock_ip(new_client));
- (cli_ip(new_client)).s_addr = addr.sin_addr.s_addr;
- cli_port(new_client) = ntohs(addr.sin_port);
+ memcpy(&cli_ip(new_client), &addr.addr, sizeof(cli_ip(new_client)));
+ cli_port(new_client) = addr.port;
if (next_target)
cli_nexttarget(new_client) = next_target;
DBufLength(&(cli_recvQ(cptr))) > feature_int(FEAT_CLIENT_FLOOD))) {
switch (os_recv_nonb(cli_fd(cptr), readbuf, sizeof(readbuf), &length)) {
case IO_SUCCESS:
- if (length) {
- cli_lasttime(cptr) = CurrentTime;
+ if (length)
+ {
+ if (!IsServer(cptr))
+ cli_lasttime(cptr) = CurrentTime;
if (cli_lasttime(cptr) > cli_since(cptr))
cli_since(cptr) = cli_lasttime(cptr);
- cli_flags(cptr) &= ~(FLAGS_PINGSENT | FLAGS_NONL);
+ ClrFlag(cptr, FLAG_PINGSENT);
+ ClrFlag(cptr, FLAG_NONL);
}
break;
case IO_BLOCKED:
break;
case IO_FAILURE:
cli_error(cptr) = errno;
- /* cptr->flags |= FLAGS_DEADSOCKET; */
+ /* SetFlag(cpt, FLAG_DEADSOCKET); */
return 0;
}
}
* For server connections, we process as many as we can without
* worrying about the time of day or anything :)
*/
- if (length > 0 && IsServer(cptr)) {
+ if (length > 0 && IsServer(cptr))
return server_dopacket(cptr, readbuf, length);
- }
- else {
+ else if (length > 0 && (IsHandshake(cptr) || IsConnecting(cptr)))
+ return connect_dopacket(cptr, readbuf, length);
+ else
+ {
/*
* Before we even think of parsing what we just read, stick
* it on the end of the receive queue and do it when its
* turn comes around.
*/
- if (length > 0 && 0 == dbuf_put(&(cli_recvQ(cptr)), readbuf, length)) {
+ if (length > 0 && dbuf_put(&(cli_recvQ(cptr)), readbuf, length) == 0)
return exit_client(cptr, cptr, &me, "dbuf_put fail");
- }
- /*
- * XXX - cptr will always be a user or unregistered
- */
- if (IsUser(cptr) &&
- DBufLength(&(cli_recvQ(cptr))) > feature_int(FEAT_CLIENT_FLOOD))
+ if (DBufLength(&(cli_recvQ(cptr))) > feature_int(FEAT_CLIENT_FLOOD))
return exit_client(cptr, cptr, &me, "Excess Flood");
while (DBufLength(&(cli_recvQ(cptr))) && !NoNewLine(cptr) &&
(IsTrusted(cptr) || cli_since(cptr) - CurrentTime < 10))
{
- /*
- * If it has become registered as a Server
- * then skip the per-message parsing below.
- */
- if (IsServer(cptr)) {
- dolen = dbuf_get(&(cli_recvQ(cptr)), readbuf, sizeof(readbuf));
- return (dolen) ? server_dopacket(cptr, readbuf, dolen) : 1;
- }
dolen = dbuf_getmsg(&(cli_recvQ(cptr)), cli_buffer(cptr), BUFSIZE);
/*
* Devious looking...whats it do ? well..if a client
* deletes the rest of the buffer contents.
* -avalon
*/
- if (0 == dolen) {
+ if (dolen == 0)
+ {
if (DBufLength(&(cli_recvQ(cptr))) < 510)
- cli_flags(cptr) |= FLAGS_NONL;
+ SetFlag(cptr, FLAG_NONL);
else
DBufClear(&(cli_recvQ(cptr)));
}
- else if (CPTR_KILLED == client_dopacket(cptr, dolen))
+ else if (client_dopacket(cptr, dolen) == CPTR_KILLED)
return CPTR_KILLED;
+ /*
+ * If it has become registered as a Server
+ * then skip the per-message parsing below.
+ */
+ if (IsHandshake(cptr) || IsServer(cptr))
+ {
+ while (-1)
+ {
+ dolen = dbuf_get(&(cli_recvQ(cptr)), readbuf, sizeof(readbuf));
+ if (dolen <= 0)
+ return 1;
+ else if (dolen == 0)
+ {
+ if (DBufLength(&(cli_recvQ(cptr))) < 510)
+ SetFlag(cptr, FLAG_NONL);
+ else
+ DBufClear(&(cli_recvQ(cptr)));
+ }
+ else if ((IsServer(cptr) &&
+ server_dopacket(cptr, readbuf, dolen) == CPTR_KILLED) ||
+ (!IsServer(cptr) &&
+ connect_dopacket(cptr, readbuf, dolen) == CPTR_KILLED))
+ return CPTR_KILLED;
+ }
+ }
}
/* If there's still data to process, wait 2 seconds first */
if (DBufLength(&(cli_recvQ(cptr))) && !NoNewLine(cptr) &&
- !t_onqueue(&(cli_proc(cptr)))) {
+ !t_onqueue(&(cli_proc(cptr))))
+ {
Debug((DEBUG_LIST, "Adding client process timer for %C", cptr));
cli_freeflag(cptr) |= FREEFLAG_TIMER;
timer_add(&(cli_proc(cptr)), client_timer_callback, cli_connect(cptr),
* be done, we loose the information about who started the connection and
* it's considered an auto connect.
*/
-int connect_server(struct ConfItem* aconf, struct Client* by,
- struct DNSReply* reply)
+int connect_server(struct ConfItem* aconf, struct Client* by)
{
struct Client* cptr = 0;
assert(0 != aconf);
return 0;
}
Debug((DEBUG_NOTICE, "Connect to %s[@%s]", aconf->name,
- ircd_ntoa((const char*) &aconf->ipnum)));
+ ircd_ntoa(&aconf->address.addr)));
if ((cptr = FindClient(aconf->name))) {
if (IsServer(cptr) || IsMe(cptr)) {
}
}
/*
- * If we dont know the IP# for this host and itis a hostname and
+ * If we dont know the IP# for this host and it is a hostname and
* not a ip# string, then try and find the appropriate host record.
*/
- if (INADDR_NONE == aconf->ipnum.s_addr) {
+ if (!irc_in_addr_valid(&aconf->address.addr)
+ && !ircd_aton(&aconf->address.addr, aconf->host)) {
char buf[HOSTLEN + 1];
- assert(0 == reply);
- if (INADDR_NONE == (aconf->ipnum.s_addr = inet_addr(aconf->host))) {
- struct DNSQuery query;
-
- query.vptr = aconf;
- query.callback = connect_dns_callback;
- host_from_uh(buf, aconf->host, HOSTLEN);
- buf[HOSTLEN] = '\0';
+ struct DNSQuery query;
- reply = gethost_byname(buf, &query);
+ query.vptr = aconf;
+ query.callback = connect_dns_callback;
+ host_from_uh(buf, aconf->host, HOSTLEN);
+ buf[HOSTLEN] = '\0';
- if (!reply) {
- aconf->dns_pending = 1;
- return 0;
- }
- memcpy(&aconf->ipnum, reply->hp->h_addr, sizeof(struct in_addr));
- }
+ gethost_byname(buf, &query);
+ aconf->dns_pending = 1;
+ return 0;
}
cptr = make_client(NULL, STAT_UNKNOWN_SERVER);
- if (reply)
- ++reply->ref_count;
- cli_dns_reply(cptr) = reply;
/*
* Copy these in so we have something for error detection.
completed_connection(cptr) : 1;
}
-/*
- * Setup local socket structure to use for binding to.
- */
-void set_virtual_host(struct in_addr addr)
-{
- memset(&VirtualHost, 0, sizeof(VirtualHost));
- VirtualHost.sin_family = AF_INET;
- VirtualHost.sin_addr.s_addr = addr.s_addr;
-}
-
/*
* Find the real hostname for the host running the server (or one which
* matches the server's name) and its primary IP#. Hostname is stored
assert(0 != ev_socket(ev));
assert(0 != s_data(ev_socket(ev)));
- con = s_data(ev_socket(ev));
+ con = (struct Connection*) s_data(ev_socket(ev));
assert(0 != con_client(con) || ev_type(ev) == ET_DESTROY);
case ET_EOF: /* end of file on socket */
Debug((DEBUG_ERROR, "READ ERROR: fd = %d %d", cli_fd(cptr),
cli_error(cptr)));
- cli_flags(cptr) |= FLAGS_DEADSOCKET;
+ SetFlag(cptr, FLAG_DEADSOCKET);
if ((IsServer(cptr) || IsHandshake(cptr)) && cli_error(cptr) == 0) {
exit_client_msg(cptr, cptr, &me, "Server %s closed the connection (%s)",
cli_name(cptr), cli_serv(cptr)->last_error_msg);
break;
case ET_WRITE: /* socket is writable */
- cli_flags(cptr) &= ~FLAGS_BLOCKED;
+ ClrFlag(cptr, FLAG_BLOCKED);
if (cli_listing(cptr) && MsgQLength(&(cli_sendQ(cptr))) < 2048)
list_next_channels(cptr, 64);
Debug((DEBUG_SEND, "Sending queued data to %C", cptr));
assert(0 != t_data(ev_timer(ev)));
assert(ET_DESTROY == ev_type(ev) || ET_EXPIRE == ev_type(ev));
- con = t_data(ev_timer(ev));
+ con = (struct Connection*) t_data(ev_timer(ev));
assert(0 != con_client(con) || ev_type(ev) == ET_DESTROY);