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/net.c

144 lines
4.3 KiB
C

/*
* 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 "main.h"
signed int init_conn(struct irc_connection* info)
{
const struct timespec retry_timeout = {3, 0.0L};
int sockfd, getaddrres, connectres;
if (info->data.addr == NULL) return -1;
struct addrinfo* conn;
for (unsigned int i = 0; i < 3; i++) {
getaddrres = getaddrinfo(info->data.addr, info->data.port, NULL, &conn);
if (getaddrres == 0) {
break;
} else {
fprintf(stderr, "%s %s:%s. %s (%i)\n", "Failed to get the address info for", info->data.addr, info->data.port, gai_strerror(getaddrres), getaddrres);
if (i == 2 || (getaddrres != EAI_AGAIN && getaddrres != EAI_NONAME)) {
freeaddrinfo(conn);
return -1;
} else {
nanosleep(&retry_timeout, NULL); /* Signals don't bother us */
}
}
}
if (getaddrres != 0) {
freeaddrinfo(conn);
return -1;
}
if ((sockfd = socket(conn->ai_family, conn->ai_socktype, conn->ai_protocol)) < 0) {
fprintf(stderr, "%s. %s (%i)\n", "Failed to open the socket", strerror(errno), errno);
return -1;
}
for (unsigned int i = 0; i < 3; i++) {
connectres = connect(sockfd, conn->ai_addr, conn->ai_addrlen);
if (connectres == 0 || connectres == EINTR) { /* TODO: Lookup if EINTR expects async conn OR connects async, assuming connects */
break;
} else {
fprintf(stderr, "%s %s:%s. %s (%i)\n", "Failed to connect to host", info->data.addr, info->data.port, strerror(errno), errno);
if (i == 2 || (connectres != EADDRNOTAVAIL && connectres != ETIMEDOUT && connectres != ECONNRESET && connectres != ECONNREFUSED)) {
close(sockfd);
return -1;
} else {
nanosleep(&retry_timeout, NULL);
}
}
}
if (connectres == -1) {
close(sockfd);
return -1;
}
info->sockfd[0] = sockfd;
return sockfd;
}
int readline_mem(struct membuffer_info* bs)
{
const int step = 513;
bool linefin = false;
if (*bs->fd <= 0)
return READLINE_SOCKET_FAIL;
// Initiate buffer with the step size
if (bs->buffer == NULL) {
if (!init_buff(bs, step))
return READLINE_BUFINIT_FAIL;
}
// Read to the last position in the buffer or at the beginning if buffer was just initiated
int b_read;
char* nl;
while (!linefin) {
if ((nl = strchr(bs->nex_line, '\n')) != NULL) {
*(nl - 1) = '\0';
bs->cur_line = bs->nex_line;
bs->nex_line = nl + 1;
break;
}
if (!realloc_full(bs, step))
return READLINE_REALLOC_FAIL;
struct pollfd pollinf[] = {{.fd = *bs->fd, .events = POLLRDNORM}};
switch (poll(pollinf, 1, 10)) {
case -1: {
if (errno != EINTR) // We don't throw a error on a damn ^C
return READLINE_POLL_FAIL;
}
default: {
if (pollinf[0].revents ^ POLLRDNORM)
return READLINE_TRYAGAIN;
}
}
b_read = read(*bs->fd, bs->append_pos, bs->end_pos - bs->append_pos);
if (b_read == EOF)
return READLINE_EOF;
bs->append_pos += b_read;
}
if (b_read == EOF)
return READLINE_EOF;
return READLINE_LINE_READY;
}
int init_buff(struct membuffer_info* bs, int size)
{
bs->buffer = malloc(size * sizeof(char));
bs->end_pos = bs->buffer + size - 1;
bs->append_pos = bs->buffer;
bs->nex_line = bs->buffer;
if (bs->buffer == NULL)
return 0;
return 1;
}
int realloc_full(struct membuffer_info* bs, int size)
{
if (bs->append_pos == bs->end_pos) {
char* newpoint;
bs->end_pos += size;
newpoint = realloc(bs->buffer, (bs->end_pos - bs->buffer) * sizeof(char));
if (newpoint != NULL) {
int offset = newpoint - bs->buffer;
// Move all pointers or you will have a BAAD time (count: 2)
bs->append_pos += offset;
bs->nex_line += offset;
bs->cur_line += offset;
bs->end_pos += offset;
bs->buffer = newpoint;
return 1;
}
return 0;
}
return 2; // Nothing to do, the buffer is not full yet
}