144 lines
4.3 KiB
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
|
|
}
|