/** * @brief Enqueue a protocol-specific handler to service a specified connection, and update any statistics accordingly. * @note If an invalid protocol is specified, the connection will be destroyed gracefully. * @param con a pointer to the connection object to be serviced. * @return This function returns no value. */ void protocol_enqueue(connection_t *con) { void *function = NULL; // Pedantic sanity checks of the passed in data. log_check(con == NULL); log_check(con->server == NULL); switch (con->server->protocol) { case (POP): stats_increment_by_name("pop.connections.total"); if (con_secure(con) == 1) stats_increment_by_name("pop.connections.secure"); function = &pop_init; break; case (IMAP): stats_increment_by_name("imap.connections.total"); if (con_secure(con) == 1) stats_increment_by_name("imap.connections.secure"); function = &imap_init; break; case (HTTP): stats_increment_by_name("http.connections.total"); if (con_secure(con) == 1) stats_increment_by_name("http.connections.secure"); function = &http_init; break; case (SMTP): stats_increment_by_name("smtp.connections.total"); if (con_secure(con) == 1) stats_increment_by_name("smtp.connections.secure"); function = &smtp_init; break; case (SUBMISSION): stats_increment_by_name("smtp.connections.total"); if (con_secure(con) == 1) stats_increment_by_name("smtp.connections.secure"); function = &submission_init; break; case (MOLTEN): stats_increment_by_name("molten.connections.total"); if (con_secure(con) == 1) stats_increment_by_name("molten.connections.secure"); function = &molten_init; break; default: log_pedantic("Protocol enqueue was passed a connection using an unsupported or unknown protocol."); con_destroy(con); return; } enqueue(function, con); return; }
// QUESTION: How many affected rows should there be? Couldn't it be much higher if there are several details deleted? int_t contact_delete(uint64_t contactnum, uint64_t usernum, uint64_t foldernum) { int64_t affected; MYSQL_BIND parameters[3]; mm_wipe(parameters, sizeof(parameters)); // Contact Number parameters[0].buffer_type = MYSQL_TYPE_LONGLONG; parameters[0].buffer_length = sizeof(uint64_t); parameters[0].buffer = &contactnum; parameters[0].is_unsigned = true; // User Number parameters[1].buffer_type = MYSQL_TYPE_LONGLONG; parameters[1].buffer_length = sizeof(uint64_t); parameters[1].buffer = &usernum; parameters[1].is_unsigned = true; // Folder parameters[2].buffer_type = MYSQL_TYPE_LONGLONG; parameters[2].buffer_length = sizeof(uint64_t); parameters[2].buffer = &foldernum; parameters[2].is_unsigned = true; // Since the updated column is always updated this function should only return 0 if the query doesn't match any rows, otherwise 1 to indicate success. if ((affected = stmt_exec_affected(stmts.delete_contact, parameters)) == -1) { log_pedantic("The contact entry time stamp update triggered an error. { usernum = %lu / foldernum = %lu / contact = %lu }", usernum, foldernum, contactnum); return -1; } log_check(affected > 2); return (int_t)affected; }
/** * @brief Delete the specified contact detail of a contact entry from the database. * @param contactnum the numerical id of the contact entry to have the specified detail removed. * @param key a managed string containing the name of the contact detail to be removed from the entry. * @return -1 on error, 0 if no matching detail was found in the database, or 1 if the delete operation was successful. */ int_t contact_detail_delete(uint64_t contactnum, stringer_t *key) { int64_t affected; MYSQL_BIND parameters[4]; mm_wipe(parameters, sizeof(parameters)); // Contact Number parameters[0].buffer_type = MYSQL_TYPE_LONGLONG; parameters[0].buffer_length = sizeof(uint64_t); parameters[0].buffer = &contactnum; parameters[0].is_unsigned = true; // Key parameters[1].buffer_type = MYSQL_TYPE_STRING; parameters[1].buffer_length = st_length_get(key); parameters[1].buffer = st_char_get(key); if ((affected = stmt_exec_affected(stmts.delete_contact_details, parameters)) == -1) { log_pedantic("The contact detail deletion request triggered an error. { contact = %lu / key = %.*s }", contactnum, st_length_int(key), st_char_get(key)); return -1; } log_check(affected > 2); return (int_t)affected; }
static void log_commit(log_header *lp) { u32t size; if (!logptr || !lp || lp-logptr>LOG_SIZEFP) { hlp_seroutstr("<< log panic: bad commit >>\n"); return; } if (!log_check(lp-logptr)) return; lp->flags |= LOGIF_USED; log_setdate(lp); // put zero to the last byte of this entry! ((char*)(lp+lp->offset))[-1] = 0; size = strlen((char*)(lp+1)); size = LOG_EntrySize(size+1); // split too long free entry if next entry is "free" if (lp->offset>size+1 && logfptr == (lp-logptr)+lp->offset) { log_header *lpnext = lp+size+1, *lpNnext = lp+lp->offset; if (lpNnext->offset) { lpnext->sign = LOG_SIGNATURE; lpnext->flags = 0; lpnext->offset = lp->offset - (size+1) + lpNnext->offset; lp->offset = size+1; lpNnext->sign = 0; // update "next free" logfptr = lpnext-logptr; } } }
/** * @brief Delete a user config entry from the database by key. * @param usernum the numerical userid of the user to whom the requested config key belongs. * @param key a managed string containing the name of the config key to be deleted. * @return 1 if the config option was successfully deleted, 0 if the config key couldn't be found in the database, or -1 on general failure. */ int_t user_config_delete(uint64_t usernum, stringer_t *key) { uint64_t affected; MYSQL_BIND parameters[4]; mm_wipe(parameters, sizeof(parameters)); // User Number parameters[0].buffer_type = MYSQL_TYPE_LONGLONG; parameters[0].buffer_length = sizeof(uint64_t); parameters[0].buffer = &usernum; parameters[0].is_unsigned = true; // Key parameters[1].buffer_type = MYSQL_TYPE_STRING; parameters[1].buffer_length = st_length_get(key); parameters[1].buffer = st_char_get(key); if (!(affected = stmt_exec_affected(stmts.delete_user_config, parameters)) == (my_ulonglong)-1) { log_pedantic("The user config deletion request triggered an error. { user = %lu / key = %.*s }", usernum, st_length_int(key), st_char_get(key)); return -1; } log_check(affected > 2); return (int_t)affected; }
void log_register( string_t s0, string_t s1, string_t function, int line_no, log_line_t line ) { if (0) { eprintf("TRACE:register (%s,%s,%s:%d)\n", s0, s1, function, line_no) ; } line->s0 = s0 ; line->s1 = s1 ; line->function = function ; line->line = line_no ; line->__logme__ = 1 ; line->next = lines ; lines = line ; if (log_check(s0, s1) || log_check_line(function, line_no)) { if (0) { eprintf("TRACE:register (%s,%s,%s:%d) ALREADY ENABLED\n", s0, s1, function, line_no) ; } lines->__logme__ = LOG_LINE_SET ; } }
/** * @brief Update a user contact entry in the database. * @param contactnum the numerical id of the contact entry to be modified. * @param usernum the numerical id of the user to whom the specified contact entry belongs. * @param cur_folder the numerical id of the parent contact containing the specified contact entry. * @param target_folder if not 0, sets the new parent contact folder to which the specified contact entry will belong. * @param name if not NULL, sets the new name of the specified contact entry. * @return -1 on error, 0 if the specified contact entry was not found in the database, or 1 if the contact entry was successfully updated. */ int_t contact_update(uint64_t contactnum, uint64_t usernum, uint64_t cur_folder, uint64_t target_folder, stringer_t *name) { int64_t affected; MYSQL_BIND parameters[5]; mm_wipe(parameters, sizeof(parameters)); // Destination Folder if (target_folder) { parameters[0].buffer_type = MYSQL_TYPE_LONGLONG; parameters[0].buffer_length = sizeof(uint64_t); parameters[0].buffer = &target_folder; parameters[0].is_unsigned = true; } else { parameters[0].buffer_type = MYSQL_TYPE_LONGLONG; parameters[0].is_null = ISNULL(true); } // Name if (!st_empty(name)) { parameters[1].buffer_type = MYSQL_TYPE_STRING; parameters[1].buffer_length = st_length_get(name); parameters[1].buffer = st_char_get(name); } else { parameters[1].buffer_type = MYSQL_TYPE_LONGLONG; parameters[1].is_null = ISNULL(true); } // Contact Number parameters[2].buffer_type = MYSQL_TYPE_LONGLONG; parameters[2].buffer_length = sizeof(uint64_t); parameters[2].buffer = &contactnum; parameters[2].is_unsigned = true; // User Number parameters[3].buffer_type = MYSQL_TYPE_LONGLONG; parameters[3].buffer_length = sizeof(uint64_t); parameters[3].buffer = &usernum; parameters[3].is_unsigned = true; // Current Folder parameters[4].buffer_type = MYSQL_TYPE_LONGLONG; parameters[4].buffer_length = sizeof(uint64_t); parameters[4].buffer = &cur_folder; parameters[4].is_unsigned = true; // Since the updated column is always updated this function should only return 0 if the query doesn't match any rows, otherwise 1 to indicate success. if ((affected = stmt_exec_affected(stmts.update_contact, parameters)) == -1) { log_pedantic("The contact entry update triggered an error. { usernum = %lu / foldernum = %lu / contact = %lu }", usernum, cur_folder, contactnum); return -1; } log_check(affected > 2); return (int_t)affected; }
static log_header *log_alloc(u32t size) { while (size && logptr && !logused) { log_header* lp = logptr + logfptr; if (!log_check(logfptr)) break; // round size to 16 size = LOG_EntrySize(size); // too large if (size>=LOG_SIZEFP-1) return 0; if (!lp->offset) lp = logptr; // search free block in cycled buffer while (lp->offset<size+1) { log_header* lpnext = lp+lp->offset; // broken header if (!log_check(lpnext-logptr)) return 0; if (!lpnext->offset) { lp = logptr; continue; } // merge next block lpnext->sign = 0; lp->offset += lpnext->offset; } if (!log_check(lp-logptr)) return 0; // split too long free entry if (lp->offset>size+3) { log_header* lpnext = lp+size+1; lpnext->sign = LOG_SIGNATURE; lpnext->flags = 0; lpnext->offset = lp->offset-size-1; lp->offset = size+1; } // update "next free" logfptr = (lp-logptr)+lp->offset; // make "empty string" in first pos *(char*)(lp+1) = 0; // mark as used lp->flags = LOGIF_USED; // return return lp; } return 0; }
/** * @brief Establish a secure channel for an inbound ssl connection before passing it off to the general server request handler. * @see protocol_enqueue() * @note This function destroys the client connection completely and returns silently upon any ssl-related failure. * @param con the The connection object associated with the inbound ssl connection. * @return This function returns no value. */ void protocol_secure(connection_t *con) { // Pedantic sanity checks of the passed in data. log_check(con == NULL); log_check(con->server == NULL); // Create a new SSL object. if (!(con->network.ssl = ssl_alloc(con->server, con->network.sockd, BIO_NOCLOSE))) { log_pedantic("The SSL connection attempt failed."); // We manually free the connection structure since calling con_destroy() would improperly decrement the statistical counters. if (con->network.ssl) ssl_free(con->network.ssl); if (con->network.sockd != -1) close(con->network.sockd); if (con->network.buffer) st_free(con->network.buffer); mutex_destroy(&(con->lock)); mm_free(con); return; } protocol_enqueue(con); return; }
/** * @brief Replace all instances of one character in a managed string with another. * @param target the input string which will be transformed by the character replacement. * @param pattern the character to be searched and replaced in the target string. * @param replacement the character to be substituted for the pattern character in the target string. * @return a pointer to the target managed string. */ stringer_t * st_swap(stringer_t *target, uchr_t pattern, uchr_t replacement) { size_t tlen; uchr_t *tptr; if (st_empty_out(target, &tptr, &tlen)) { log_pedantic("Sanity check failed. Passed a NULL pointer."); return target; } log_check(pattern == replacement); // Increment through and replace the pattern. for (size_t i = 0; i < tlen; i++) { if (*tptr == pattern) *tptr = replacement; tptr++; } return target; }
// called from mainloop at background priority to write telemetry log data to log file void telemetry_log(void) { if (lb_in_use == 1) { if (lb2_end_index) { log_write(logbuf2, lb2_end_index); lb2_end_index = 0; } } else { if (lb1_end_index) { log_write(logbuf1, lb1_end_index); lb1_end_index = 0; } } log_check(); }
/** * @brief Update a specified contact detail in the database, or insert it if it does not exist. * @param contactnum the numerical id of the contact entry to be modified. * @param key a managed string containing the name of the contact detail to be updated. * @param value a managed string containing the new value of the specified contact detail. * @param flags a bitmask of flags to be associated with the specified contact entry detail. * @return -1 on error, 0 if no update was necessary, 1 if a new contact detail was inserted into the database, or 2 if the * specified contact detail was updated successfully. */ int_t contact_detail_upsert(uint64_t contactnum, stringer_t *key, stringer_t *value, uint64_t flags) { int64_t affected; MYSQL_BIND parameters[4]; mm_wipe(parameters, sizeof(parameters)); // Contact Number parameters[0].buffer_type = MYSQL_TYPE_LONGLONG; parameters[0].buffer_length = sizeof(uint64_t); parameters[0].buffer = &contactnum; parameters[0].is_unsigned = true; // Key parameters[1].buffer_type = MYSQL_TYPE_STRING; parameters[1].buffer_length = st_length_get(key); parameters[1].buffer = st_char_get(key); // Value parameters[2].buffer_type = MYSQL_TYPE_STRING; parameters[2].buffer_length = st_length_get(value); parameters[2].buffer = st_char_get(value); // Flags parameters[3].buffer_type = MYSQL_TYPE_LONGLONG; parameters[3].buffer_length = sizeof(uint64_t); parameters[3].buffer = &flags; parameters[3].is_unsigned = true; if ((affected = stmt_exec_affected(stmts.upsert_contact_detail, parameters)) == -1) { log_pedantic("The contact detail upsert triggered an error. { contact = %lu / key = %.*s }", contactnum, st_length_int(key), st_char_get(key)); return -1; } log_check(affected > 2); return (int_t)affected; }