aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gnutls_network.c17
-rw-r--r--protocols.c3
-rw-r--r--protocols.h3
-rw-r--r--protocols/inspircd2.c135
-rw-r--r--protocols/inspircd2.h5
-rw-r--r--server_network.c44
-rw-r--r--server_network.h8
7 files changed, 189 insertions, 26 deletions
diff --git a/gnutls_network.c b/gnutls_network.c
index 5105ce1..68cd251 100644
--- a/gnutls_network.c
+++ b/gnutls_network.c
@@ -61,15 +61,14 @@ int gnutls_send(void *session, struct string msg) {
ssize_t res;
do {
res = gnutls_record_send(*((gnutls_session_t*)session), msg.data, msg.len);
- } while (res == -GNUTLS_E_INTERRUPTED || res == -GNUTLS_E_AGAIN);
+ } while (res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN);
if (res < 0 || (size_t)res > msg.len) { // res > len shouldn't be possible, but is still an error
return 1;
- } else if (res > 0) {
- msg.len -= (size_t)res;
- msg.data += (size_t)res;
+ } else if ((size_t)res == msg.len) {
+ break;
}
- } while (msg.len > 0);
+ } while (1);
return 0;
}
@@ -78,10 +77,10 @@ size_t gnutls_recv(void *session, char *data, size_t len, char *err) {
ssize_t res;
do {
res = gnutls_record_recv(*((gnutls_session_t*)session), data, len);
- } while (res < 0 && (res == -GNUTLS_E_INTERRUPTED || res == -GNUTLS_E_AGAIN));
+ } while (res < 0 && (res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN));
if (res < 0) {
- if (res == -GNUTLS_E_TIMEDOUT) {
+ if (res == GNUTLS_E_TIMEDOUT) {
*err = 1;
} else {
*err = 3;
@@ -146,7 +145,7 @@ int gnutls_connect(void **handle, struct string address, struct string port, str
do {
res = gnutls_handshake(*session);
- } while (res == -GNUTLS_E_INTERRUPTED || res == -GNUTLS_E_AGAIN);
+ } while (res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN);
if (res < 0)
goto gnutls_connect_deinit_session;
@@ -210,7 +209,7 @@ int gnutls_accept(int listen_fd, void **handle, struct string *addr) {
int res;
do {
res = gnutls_handshake(*session);
- } while (res == -GNUTLS_E_INTERRUPTED || res == -GNUTLS_E_AGAIN);
+ } while (res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN);
if (res != GNUTLS_E_SUCCESS)
goto gnutls_accept_deinit_session;
diff --git a/protocols.c b/protocols.c
index 59a1a32..1adb383 100644
--- a/protocols.c
+++ b/protocols.c
@@ -39,6 +39,9 @@ struct protocol protocols[NUM_PROTOCOLS] = {
.autoconnect = inspircd2_protocol_autoconnect,
.update_propagations = inspircd2_protocol_update_propagations,
+ .propagate_new_server = inspircd2_protocol_propagate_new_server,
+ .propagate_unlink = inspircd2_protocol_propagate_unlink,
+
.do_unlink = inspircd2_protocol_do_unlink,
},
#endif
diff --git a/protocols.h b/protocols.h
index b91a6bf..3b4aca3 100644
--- a/protocols.h
+++ b/protocols.h
@@ -33,6 +33,9 @@ struct protocol {
void * (*autoconnect)(void *config);
void (*update_propagations)(void);
+ void (*propagate_new_server)(struct string from, struct string attached_to, struct string sid, struct server_info *info);
+ void (*propagate_unlink)(struct string from, struct server_info *a, struct server_info *b, size_t protocol);
+
void (*do_unlink)(struct server_info *a, struct server_info *b);
};
diff --git a/protocols/inspircd2.c b/protocols/inspircd2.c
index 5cf05c1..496c0d0 100644
--- a/protocols/inspircd2.c
+++ b/protocols/inspircd2.c
@@ -78,8 +78,6 @@ void * inspircd2_protocol_connection(void *type) {
free(type);
}
- struct string full_msg = {.data = malloc(0), .len = 0}; // TODO: move this down below after incoming connections are handled
-
if (!is_incoming) {
networks[net].send(handle, STRING("CAPAB START 1202\nCAPAB END\n"));
@@ -94,6 +92,8 @@ void * inspircd2_protocol_connection(void *type) {
networks[net].send(handle, STRING("\n"));
}
+ struct string full_msg = {.data = malloc(0), .len = 0};
+
while (1) {
size_t msg_len;
size_t old_len;
@@ -297,8 +297,11 @@ void * inspircd2_protocol_connection(void *type) {
inspircd2_protocol_handle_connection_close:
free(full_msg.data);
- if (ready)
- unlink_server(get_table_index(server_list, config->sid), get_table_index(server_list, SID), INSPIRCD2_PROTOCOL);
+ if (ready) {
+ pthread_mutex_lock(&(state_lock));
+ unlink_server(config->sid, get_table_index(server_list, config->sid), get_table_index(server_list, SID), INSPIRCD2_PROTOCOL);
+ pthread_mutex_unlock(&(state_lock));
+ }
networks[net].close(fd, handle);
free(address.data);
@@ -350,6 +353,7 @@ void inspircd2_protocol_update_propagations_inner(struct server_info *source) {
adjacent->next = adjacent->sid;
} else {
adjacent->next = source->next;
+ adjacent->handle = source->handle;
}
inspircd2_protocol_update_propagations_inner(adjacent);
}
@@ -368,11 +372,87 @@ void inspircd2_protocol_update_propagations(void) {
inspircd2_protocol_update_propagations_inner(self);
}
+void inspircd2_protocol_propagate_new_server(struct string from, struct string attached_to, struct string sid, struct server_info *info) {
+ struct server_info *self = get_table_index(server_list, SID);
+
+ for (size_t i = 0; i < self->connected_to.len; i++) {
+ struct server_info *adjacent = self->connected_to.array[i].ptr;
+ if (adjacent->protocol != INSPIRCD2_PROTOCOL || STRING_EQ(from, adjacent->sid))
+ continue; // Not ours or it's the source of this message
+
+ networks[adjacent->net].send(adjacent->handle, STRING(":"));
+
+ if (info->protocol == INSPIRCD2_PROTOCOL)
+ networks[adjacent->net].send(adjacent->handle, attached_to);
+ else // Just pretend servers connected via a different protocol are connected directly to us
+ networks[adjacent->net].send(adjacent->handle, SID);
+
+ networks[adjacent->net].send(adjacent->handle, STRING(" SERVER "));
+ networks[adjacent->net].send(adjacent->handle, info->name);
+ networks[adjacent->net].send(adjacent->handle, STRING(" * 0 "));
+ networks[adjacent->net].send(adjacent->handle, sid);
+ networks[adjacent->net].send(adjacent->handle, STRING(" :"));
+ networks[adjacent->net].send(adjacent->handle, info->fullname);
+ networks[adjacent->net].send(adjacent->handle, STRING("\n"));
+
+ networks[adjacent->net].send(adjacent->handle, STRING(":"));
+ networks[adjacent->net].send(adjacent->handle, sid);
+ networks[adjacent->net].send(adjacent->handle, STRING(" BURST "));
+
+ time_t current = time(0);
+ struct string current_time;
+ char err = unsigned_to_str((size_t)current, &current_time);
+
+ if (current < 0 || err) {
+ networks[adjacent->net].send(adjacent->handle, STRING("0"));
+ } else {
+ networks[adjacent->net].send(adjacent->handle, current_time);
+ free(current_time.data);
+ }
+
+ networks[adjacent->net].send(adjacent->handle, STRING("\n:"));
+ networks[adjacent->net].send(adjacent->handle, sid);
+ networks[adjacent->net].send(adjacent->handle, STRING(" ENDBURST\n"));
+ }
+}
+
+void inspircd2_protocol_propagate_unlink(struct string from, struct server_info *a, struct server_info *b, size_t protocol) {
+ struct server_info *source;
+ struct server_info *target;
+ if (a->distance == 0 && !STRING_EQ(a->sid, SID)) {
+ source = b;
+ target = a;
+ } else if (b->distance == 0 && !STRING_EQ(b->sid, SID)) {
+ source = a;
+ target = b;
+ } else {
+ return;
+ }
+
+ struct server_info *self = get_table_index(server_list, SID);
+ for (size_t i = 0; i < self->connected_to.len; i++) {
+ struct server_info *adjacent = self->connected_to.array[i].ptr;
+ if (STRING_EQ(from, adjacent->next) || adjacent->protocol != INSPIRCD2_PROTOCOL)
+ continue;
+
+ networks[adjacent->net].send(adjacent->handle, STRING(":"));
+ if (protocol == INSPIRCD2_PROTOCOL)
+ networks[adjacent->net].send(adjacent->handle, source->sid);
+ else
+ networks[adjacent->net].send(adjacent->handle, SID);
+ networks[adjacent->net].send(adjacent->handle, STRING(" SQUIT "));
+ networks[adjacent->net].send(adjacent->handle, target->sid);
+ networks[adjacent->net].send(adjacent->handle, STRING(" :\n"));
+ }
+}
+
void inspircd2_protocol_do_unlink_inner(struct server_info *target) {
+ target->distance = 1; // Reusing distance for `have passed`, since its set to 0 bc severed anyways
+
unsigned char i = 0;
- while (target->connected_to.len > 1) {
+ while (target->connected_to.len > i) {
struct server_info *adjacent = target->connected_to.array[i].ptr;
- if (adjacent->distance < target->distance) {
+ if (adjacent->distance != 0) {
i = 1;
continue;
}
@@ -384,7 +464,7 @@ void inspircd2_protocol_do_unlink_inner(struct server_info *target) {
}
void inspircd2_protocol_do_unlink(struct server_info *a, struct server_info *b) {
- if (a->distance > b->distance) {
+ if (a->distance == 0 && !STRING_EQ(a->sid, SID)) {
inspircd2_protocol_do_unlink_inner(a);
remove_table_index(&(b->connected_to), a->sid);
remove_table_index(&(server_list), a->sid);
@@ -397,6 +477,35 @@ void inspircd2_protocol_do_unlink(struct server_info *a, struct server_info *b)
}
}
+void inspircd2_protocol_introduce_servers_to_inner(size_t net, void *handle, struct string source, struct server_info *target) {
+ networks[net].send(handle, STRING(":"));
+ networks[net].send(handle, source);
+ networks[net].send(handle, STRING(" SERVER "));
+ networks[net].send(handle, target->name);
+ networks[net].send(handle, STRING(" * 0 "));
+ networks[net].send(handle, target->sid);
+ networks[net].send(handle, STRING(" :"));
+ networks[net].send(handle, target->fullname);
+ networks[net].send(handle, STRING("\n"));
+
+ for (size_t i = 0; i < target->connected_to.len; i++) {
+ struct server_info *adjacent = target->connected_to.array[i].ptr;
+ if (adjacent->distance > target->distance) {
+ inspircd2_protocol_introduce_servers_to_inner(net, handle, target->sid, adjacent);
+ }
+ }
+}
+
+void inspircd2_protocol_introduce_servers_to(size_t net, void *handle) {
+ struct server_info *self = get_table_index(server_list, SID);
+ for (size_t i = 0; i < self->connected_to.len; i++) {
+ struct server_info *info = self->connected_to.array[i].ptr;
+ if (info->protocol == INSPIRCD2_PROTOCOL) { // This server hasn't been added to the list yet, so no need to check for that
+ inspircd2_protocol_introduce_servers_to_inner(net, handle, SID, info);
+ }
+ }
+}
+
// CAPAB <type> [<args> [, ...]]
int inspircd2_protocol_init_handle_capab(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config **config, char is_incoming) {
if (argc < 1) {
@@ -469,13 +578,17 @@ int inspircd2_protocol_init_handle_server(struct string source, size_t argc, str
networks[net].send(handle, SID);
networks[net].send(handle, STRING(" BURST "));
networks[net].send(handle, time);
- networks[net].send(handle, STRING("\n:"));
+ networks[net].send(handle, STRING("\n"));
+
+ inspircd2_protocol_introduce_servers_to(net, handle);
+
+ networks[net].send(handle, STRING(":"));
networks[net].send(handle, SID);
networks[net].send(handle, STRING(" ENDBURST\n"));
free(time.data);
- if (add_server(SID, argv[3], argv[0], argv[4], INSPIRCD2_PROTOCOL, net) != 0) {
+ if (add_server((*config)->sid, SID, argv[3], argv[0], argv[4], INSPIRCD2_PROTOCOL, net, handle) != 0) {
WRITES(2, STRING("ERROR: Unable to add server!\r\n"));
return -1;
}
@@ -508,7 +621,7 @@ int inspircd2_protocol_handle_server(struct string source, size_t argc, struct s
return -1;
}
- if (add_server(source, argv[3], argv[0], argv[4], INSPIRCD2_PROTOCOL, net) != 0) {
+ if (add_server(config->sid, source, argv[3], argv[0], argv[4], INSPIRCD2_PROTOCOL, net, handle) != 0) {
WRITES(2, STRING("ERROR: Unable to add server!\r\n"));
return -1;
}
@@ -538,7 +651,7 @@ int inspircd2_protocol_handle_squit(struct string source, size_t argc, struct st
return -1;
}
- unlink_server(a, b, INSPIRCD2_PROTOCOL);
+ unlink_server(config->sid, a, b, INSPIRCD2_PROTOCOL);
return 0;
}
diff --git a/protocols/inspircd2.h b/protocols/inspircd2.h
index f0358d3..48a6f59 100644
--- a/protocols/inspircd2.h
+++ b/protocols/inspircd2.h
@@ -41,10 +41,15 @@ void * inspircd2_protocol_connection(void *type);
void * inspircd2_protocol_autoconnect(void *type);
void inspircd2_protocol_update_propagations(void);
+void inspircd2_protocol_propagate_new_server(struct string from, struct string attached_to, struct string sid, struct server_info *info);
+void inspircd2_protocol_propagate_unlink(struct string from, struct server_info *a, struct server_info *b, size_t protocol);
+
void inspircd2_protocol_do_unlink(struct server_info *a, struct server_info *b);
void inspircd2_protocol_update_propagations_inner(struct server_info *source);
+void inspircd2_protocol_do_unlink_inner(struct server_info *source);
+
int inspircd2_protocol_init_handle_server(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config **config, char is_incoming);
int inspircd2_protocol_init_handle_capab(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config **config, char is_incoming);
diff --git a/server_network.c b/server_network.c
index c193a54..7f481ec 100644
--- a/server_network.c
+++ b/server_network.c
@@ -189,7 +189,7 @@ void * server_accept_thread(void *type) {
}
}
-int add_server(struct string attached_to, struct string sid, struct string name, struct string fullname, size_t protocol, size_t net) {
+int add_server(struct string from, struct string attached_to, struct string sid, struct string name, struct string fullname, size_t protocol, size_t net, void *handle) {
struct server_info *attached = get_table_index(server_list, attached_to);
if (!attached)
return 1;
@@ -204,6 +204,7 @@ int add_server(struct string attached_to, struct string sid, struct string name,
new_info->protocol = protocol;
new_info->net = net;
+ new_info->handle = handle;
new_info->sid.data = malloc(sid.len);
if (!new_info->sid.data)
@@ -211,6 +212,18 @@ int add_server(struct string attached_to, struct string sid, struct string name,
memcpy(new_info->sid.data, sid.data, sid.len);
new_info->sid.len = sid.len;
+ new_info->name.data = malloc(name.len);
+ if (!new_info->name.data)
+ goto add_server_free_sid;
+ memcpy(new_info->name.data, name.data, name.len);
+ new_info->name.len = name.len;
+
+ new_info->fullname.data = malloc(fullname.len);
+ if (!new_info->fullname.data)
+ goto add_server_free_name;
+ memcpy(new_info->fullname.data, fullname.data, fullname.len);
+ new_info->fullname.len = fullname.len;
+
// new_info->next shares string with sid of the server it points to
new_info->connected_to = (struct table){.array = malloc(0), .len = 0};
@@ -222,11 +235,18 @@ int add_server(struct string attached_to, struct string sid, struct string name,
new_info->user_list = (struct table){.array = malloc(0), .len = 0};
- protocols[protocol].update_propagations();
-
if (set_table_index(&(server_list), sid, new_info) != 0)
goto add_server_remove_attached_connected_to;
+ protocols[protocol].update_propagations();
+
+#ifdef USE_HAXIRCD_PROTOCOL
+ protocols[HAXIRCD_PROTOCOL].propagate_new_server(from, attached_to, sid, new_info);
+#endif
+#ifdef USE_INSPIRCD2_PROTOCOL
+ protocols[INSPIRCD2_PROTOCOL].propagate_new_server(from, attached_to, sid, new_info);
+#endif
+
return 0;
add_server_remove_attached_connected_to:
@@ -235,6 +255,10 @@ int add_server(struct string attached_to, struct string sid, struct string name,
clear_table(&(new_info->connected_to));
add_server_free_connected_to:
free(new_info->connected_to.array);
+ free(new_info->fullname.data);
+ add_server_free_name:
+ free(new_info->name.data);
+ add_server_free_sid:
free(new_info->sid.data);
add_server_free_new_info:
free(new_info);
@@ -260,9 +284,21 @@ void update_all_propagations(void) {
#endif
}
-void unlink_server(struct server_info *a, struct server_info *b, size_t protocol) {
+void unlink_server(struct string from, struct server_info *a, struct server_info *b, size_t protocol) {
if (!has_table_index(a->connected_to, b->sid))
return;
+ remove_table_index(&(a->connected_to), b->sid);
+ remove_table_index(&(b->connected_to), a->sid);
+
+ protocols[protocol].update_propagations();
+
+#ifdef USE_HAXIRCD_PROTOCOL
+ protocols[HAXIRCD_PROTOCOL].propagate_unlink(from, a, b, protocol);
+#endif
+#ifdef USE_INSPIRCD2_PROTOCOL
+ protocols[INSPIRCD2_PROTOCOL].propagate_unlink(from, a, b, protocol);
+#endif
+
protocols[protocol].do_unlink(a, b);
}
diff --git a/server_network.h b/server_network.h
index 7c28cb2..ac4a23e 100644
--- a/server_network.h
+++ b/server_network.h
@@ -47,6 +47,8 @@ struct server_connection_info {
struct server_info {
struct string sid;
+ struct string name;
+ struct string fullname;
struct string next; // Self for self, else which server we should send a message to to get to this server
@@ -54,6 +56,8 @@ struct server_info {
struct table user_list;
+ void *handle;
+
size_t protocol;
size_t net;
@@ -68,11 +72,11 @@ void * server_accept_thread(void *type);
void * handle_server_thread(void *type);
-int add_server(struct string attached_to, struct string sid, struct string name, struct string fullname, size_t protocol, size_t net);
+int add_server(struct string from, struct string attached_to, struct string sid, struct string name, struct string fullname, size_t protocol, size_t net, void *handle);
void free_server(struct server_info *server);
void update_all_propagations(void);
-void unlink_server(struct server_info *a, struct server_info *b, size_t protocol);
+void unlink_server(struct string from, struct server_info *a, struct server_info *b, size_t protocol);
extern struct table server_config;