/**
 * @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;

}
Exemple #2
0
// 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;
}
Exemple #3
0
/**
 * @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;
}
Exemple #4
0
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;
}
Exemple #6
0
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 ;
    }
    
}
Exemple #7
0
/**
 * @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;
}
Exemple #8
0
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;
}
Exemple #10
0
/**
 * @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;
}
Exemple #11
0
// 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();
}
Exemple #12
0
/**
 * @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;
}