This repository has been archived on 2021-02-08. You can view files and clone it, but cannot push or open issues or pull requests.
uIRCd/src/connection.c

187 lines
6.6 KiB
C
Raw Normal View History

2020-12-08 02:16:12 +00:00
/*
* This file is part of uIRCd. (https://git.redxen.eu/caskd/uIRCd)
* Copyright (c) 2019, 2020 Alex-David Denes
*
* uIRCd 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 3 of the License, or
* any later version.
*
* uIRCd 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.
*
* You should have received a copy of the GNU General Public License
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
*/
#include "connection.h"
signed int
init_connection(Connection* info)
2020-12-08 02:16:12 +00:00
{
int sockfd, getaddrres, connectres;
2020-12-08 02:16:12 +00:00
struct addrinfo* conn;
2020-12-08 22:20:42 +00:00
if ((getaddrres = getaddrinfo(info->data.address, info->data.service, NULL, &conn)) != 0) {
2020-12-08 02:16:12 +00:00
freeaddrinfo(conn);
if (getaddrres != EAI_AGAIN && getaddrres != EAI_NONAME) {
LOG(LOG_ERROR,
"Failed to get address info for " ADDRFMT ". " ERRNOFMT,
info->data.address,
info->data.service,
gai_strerror(getaddrres),
getaddrres);
2020-12-08 02:16:12 +00:00
return INIT_HARDFAIL;
} else {
LOG(LOG_WARN,
"Failed to get address info for " ADDRFMT ". " ERRNOFMT,
info->data.address,
info->data.service,
gai_strerror(getaddrres),
getaddrres);
2020-12-08 02:16:12 +00:00
return INIT_SOFTFAIL;
}
}
if ((sockfd = socket(conn->ai_family, conn->ai_socktype, conn->ai_protocol)) < 0) {
2020-12-08 22:20:42 +00:00
LOG(LOG_ERROR, "Failed to open a socket for " ADDRFMT ". " ERRNOFMT, info->data.address, info->data.service, strerror(errno), errno);
2020-12-08 02:16:12 +00:00
freeaddrinfo(conn);
return INIT_HARDFAIL;
}
if ((connectres = connect(sockfd, conn->ai_addr, conn->ai_addrlen)) == -1) {
close(sockfd);
freeaddrinfo(conn);
if (errno != EADDRNOTAVAIL && errno != ETIMEDOUT && errno != ECONNRESET && errno != ECONNREFUSED) {
LOG(LOG_ERROR,
"Failed to connect to host " ADDRFMT ". " ERRNOFMT,
info->data.address,
info->data.service,
strerror(errno),
errno);
2020-12-08 02:16:12 +00:00
return INIT_HARDFAIL;
} else {
LOG(LOG_WARN,
"Failed to connect to host " ADDRFMT ". " ERRNOFMT,
info->data.address,
info->data.service,
strerror(errno),
errno);
2020-12-08 02:16:12 +00:00
return INIT_SOFTFAIL;
}
}
freeaddrinfo(conn);
return sockfd;
}
int
auto_msg_actions(IRC_Message* message, Connection* connection, Buffer_Info* buf)
2020-12-08 02:16:12 +00:00
{
signed long len;
time_t ctime = time(NULL);
2020-12-08 02:16:12 +00:00
switch (message->cmd) {
case (PING): {
LOG(LOG_DEBUG, "Auto-replying to ping \"%s\".", message->args[0]);
if ((len = Assm_mesg(buf->buffer, Assm_cmd_PONG(message->args[0], NULL), sizeof(buf->buffer))) > 0)
if (flush_buffer(buf->buffer, (size_t) len, buf->fd) == -1) {
LOG(LOG_WARN,
"Couldn't pong " ADDRFMT ". " ERRNOFMT,
connection->data.address,
connection->data.service,
strerror(errno),
errno);
2020-12-08 22:20:42 +00:00
connection->info.state = CONN_RECONNECTING;
2020-12-08 02:16:12 +00:00
return 0;
}
break;
}
case (PONG): {
if (message->trailing && message->args[1] != NULL) {
LOG(LOG_DEBUG, "Got PONG back with message \"%s\".", message->args[1]);
2020-12-08 22:20:42 +00:00
connection->info.l_pong = ctime;
2020-12-08 02:16:12 +00:00
}
break;
}
2020-12-08 22:20:42 +00:00
/* Autojoin channels from current connection on first response from the server */
2020-12-08 02:16:12 +00:00
case (RPL_WELCOME): {
2020-12-08 22:20:42 +00:00
LOG(LOG_INFO, "Connection established to " ADDRFMT ".", connection->data.address, connection->data.service);
connection->info.state = CONN_ACTIVE;
for (unsigned int i = 0; connection->data.channels != NULL && connection->data.channels[i] != NULL; i++) {
LOG(LOG_VERBOSE,
"Auto-joining channel \"%s\" on " ADDRFMT ".",
connection->data.channels[i]->name,
connection->data.address,
2020-12-08 22:20:42 +00:00
connection->data.service);
if ((len = Assm_mesg(buf->buffer, Assm_cmd_JOIN(connection->data.channels[i]->name, NULL), sizeof(buf->buffer)))
> 0) {
if (flush_buffer(buf->buffer, (size_t) len, buf->fd) == -1) {
LOG(LOG_WARN,
"Couldn't auto-join channels \"%s\" " ADDRFMT ". " ERRNOFMT,
connection->data.channels[i]->name,
connection->data.address,
connection->data.service,
strerror(errno),
2020-12-08 22:20:42 +00:00
errno);
connection->info.state = CONN_RECONNECTING;
2020-12-08 02:16:12 +00:00
return 0;
}
}
}
break;
}
/*
case (CAP): {
if (message->args[1] != NULL && strcmp(message->args[1], "LS") == 0) {
2020-12-08 22:20:42 +00:00
LOG(LOG_VERBOSE, "Requesting capabilities \"%s\" on " ADDRFMT ".", message->args[2], connection->data.address,
2020-12-08 02:16:12 +00:00
connection->data.port);
if ((len = Assm_mesg(buf->buffer, Assm_cmd_CAP_REQ(message->args[2]), sizeof(buf->buffer))) > 0) {
if (flush_buffer(buf->buffer, (size_t)len, buf->fd) == -1) {
LOG(LOG_WARN, "Couldn't request capabilities \"%s\" on " ADDRFMT ". " ERRNOFMT, message->args[2],
2020-12-08 22:20:42 +00:00
connection->data.address, connection->data.port, strerror(errno), errno);
2020-12-08 02:16:12 +00:00
connection->state = CONN_RECONNECTING;
return 0;
}
}
} else if (message->args[1] != NULL && strcmp(message->args[1], "ACK") == 0) {
2020-12-08 22:20:42 +00:00
LOG(LOG_VERBOSE, "Ending capability negotiation on " ADDRFMT ".", connection->data.address, connection->data.port);
2020-12-08 02:16:12 +00:00
if ((len = Assm_mesg(buf->buffer, Assm_cmd_CAP_END(), sizeof(buf->buffer))) > 0) {
if (flush_buffer(buf->buffer, (size_t)len, buf->fd) == -1) {
LOG(LOG_WARN, "Couldn't end capability negotiation on " ADDRFMT ". " ERRNOFMT,
connection->data.address, connection->data.port, strerror(errno), errno); connection->state = CONN_RECONNECTING; return 0;
2020-12-08 02:16:12 +00:00
}
}
}
break;
}
*/
case (ERROR): {
LOG(LOG_ERROR,
"Received error on connection " ADDRFMT " with the message \"%s\".",
connection->data.address,
connection->data.service,
message->args[0]);
2020-12-08 02:16:12 +00:00
break;
}
case (ERR_NICKNAMEINUSE):
case (ERR_NICKCOLLISION): {
LOG(LOG_ERROR,
"Nickname %s is already taken on " ADDRFMT ".",
connection->user.nickname,
connection->data.address,
2020-12-08 22:20:42 +00:00
connection->data.service);
connection->info.state = CONN_RECONNECTING;
2020-12-08 02:16:12 +00:00
break;
}
}
return 1;
}
ssize_t
get_connstr(char* buf, size_t maxlen, Connection* conn)
2020-12-08 02:16:12 +00:00
{
int len = 0;
2020-12-08 22:20:42 +00:00
LOG(LOG_DEBUG, "Preparing path: " ADDRFMT, conn->data.address, conn->data.service);
if ((len = snprintf(buf, maxlen, "%s.%s", conn->data.address, conn->data.service)) <= 0) return -1;
2020-12-08 02:16:12 +00:00
return len;
}