diff options
-rw-r--r-- | gnutls_network.c | 17 | ||||
-rw-r--r-- | protocols.c | 3 | ||||
-rw-r--r-- | protocols.h | 3 | ||||
-rw-r--r-- | protocols/inspircd2.c | 135 | ||||
-rw-r--r-- | protocols/inspircd2.h | 5 | ||||
-rw-r--r-- | server_network.c | 44 | ||||
-rw-r--r-- | server_network.h | 8 |
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, ¤t_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; |