Desarrollo de sistemas, administración, DevOps y seguridad en entornos profesionales
Para desarrollar en C++ en Linux necesitamos instalar las herramientas básicas:
# Instalar compilador y herramientas básicas
sudo apt update
sudo apt install build-essential g++ cmake git
# Instalar herramientas de desarrollo adicionales
sudo apt install valgrind gdb clang-format cppcheck
Un programa básico en C++ para Linux:
#include <iostream>
#include <unistd.h> // Para funciones POSIX como getpid()
int main() {
std::cout << "¡Hola Mundo desde Linux!" << std::endl;
std::cout << "PID del proceso: " << getpid() << std::endl;
return 0;
}
g++ -o hello_world hello_world.cpp
./hello_world
g++ -Wall -Wextra -Werror -pedantic -std=c++17
Ejemplo de cómo listar y manejar procesos:
#include <iostream>
#include <sys/types.h>
#include <dirent.h>
#include <cstdio>
void list_processes() {
DIR *dir;
struct dirent *ent;
if ((dir = opendir("/proc")) != nullptr) {
while ((ent = readdir(dir)) != nullptr) {
// Solo directorios con nombres numéricos (PIDs)
if (ent->d_type == DT_DIR && isdigit(ent->d_name[0])) {
std::cout << "PID: " << ent->d_name << std::endl;
// Leer el archivo cmdline para el nombre del proceso
char path[256];
snprintf(path, sizeof(path), "/proc/%s/cmdline", ent->d_name);
FILE *cmdline = fopen(path, "r");
if (cmdline) {
char cmd[1024];
if (fgets(cmd, sizeof(cmd), cmdline) {
std::cout << "Comando: " << cmd << std::endl;
}
fclose(cmdline);
}
}
}
closedir(dir);
} else {
perror("No se pudo abrir /proc");
}
}
int main() {
std::cout << "Listado de procesos en ejecución:" << std::endl;
list_processes();
return 0;
}
Trabajando con el sistema de archivos:
#include <iostream>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
void check_file_permissions(const char* filename) {
struct stat file_stat;
if (stat(filename, &file_stat) == -1) {
perror("stat");
return;
}
std::cout << "Información para: " << filename << std::endl;
std::cout << "Tamaño: " << file_stat.st_size << " bytes" << std::endl;
// Permisos del archivo
std::cout << "Permisos: ";
std::cout << (S_ISDIR(file_stat.st_mode) ? "d" : "-");
std::cout << (file_stat.st_mode & S_IRUSR) ? "r" : "-");
std::cout << (file_stat.st_mode & S_IWUSR) ? "w" : "-");
std::cout << (file_stat.st_mode & S_IXUSR) ? "x" : "-");
std::cout << (file_stat.st_mode & S_IRGRP) ? "r" : "-");
std::cout << (file_stat.st_mode & S_IWGRP) ? "w" : "-");
std::cout << (file_stat.st_mode & S_IXGRP) ? "x" : "-");
std::cout << (file_stat.st_mode & S_IROTH) ? "r" : "-");
std::cout << (file_stat.st_mode & S_IWOTH) ? "w" : "-");
std::cout << (file_stat.st_mode & S_IXOTH) ? "x" : "-");
std::cout << std::endl;
// Cambiar permisos
if (chmod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
perror("chmod");
}
}
int main() {
const char* filename = "ejemplo.txt";
// Crear un archivo
int fd = open(filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (fd == -1) {
perror("open");
return 1;
}
const char* content = "Contenido de ejemplo\n";
write(fd, content, strlen(content));
close(fd);
// Verificar permisos
check_file_permissions(filename);
return 0;
}
Ejemplo de automatización con C++:
#include <iostream>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <vector>
#include <string>
class CommandExecutor {
public:
static int execute(const std::string& command) {
int status = system(command.c_str());
if (WIFEXITED(status)) {
return WEXITSTATUS(status);
}
return -1;
}
static std::string executeWithOutput(const std::string& command) {
std::string result;
FILE* pipe = popen(command.c_str(), "r");
if (!pipe) return "ERROR";
char buffer[128];
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
result += buffer;
}
pclose(pipe);
return result;
}
};
int main() {
// Ejemplo: Actualizar el sistema
std::cout << "Actualizando paquetes..." << std::endl;
int update_status = CommandExecutor::execute("sudo apt update && sudo apt upgrade -y");
if (update_status == 0) {
std::cout << "Actualización completada con éxito" << std::endl;
} else {
std::cerr << "Error en la actualización" << std::endl;
return 1;
}
// Ejemplo: Obtener información del sistema
std::cout << "\nInformación del sistema:" << std::endl;
std::string uname = CommandExecutor::executeWithOutput("uname -a");
std::cout << uname << std::endl;
// Ejemplo: Verificar espacio en disco
std::string disk = CommandExecutor::executeWithOutput("df -h");
std::cout << "\nUso de disco:" << std::endl << disk << std::endl;
return 0;
}
Configuración de un proyecto profesional con CMake:
cmake_minimum_required(VERSION 3.10)
project(DevOpsAutomation LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Configuraciones de compilación
option(ENABLE_TESTING "Habilitar pruebas unitarias" ON)
option(ENABLE_COVERAGE "Habilitar cobertura de código" OFF)
# Configuraciones de warnings
add_compile_options(
-Wall
-Wextra
-Werror
-pedantic
-Wconversion
-Wsign-conversion
)
# Configuración para cobertura
if(ENABLE_COVERAGE)
add_compile_options(--coverage -O0 -g)
add_link_options(--coverage)
endif()
# Archivos fuente
set(SOURCES
src/main.cpp
src/automation.cpp
src/command_executor.cpp
)
# Ejecutable principal
add_executable(devops-automation ${SOURCES})
# Pruebas unitarias
if(ENABLE_TESTING)
enable_testing()
add_subdirectory(tests)
endif()
# Instalación
install(TARGETS devops-automation DESTINATION bin)
Ejemplo de cómo interactuar con Git mediante libgit2:
#include <iostream>
#include <git2.h>
class GitRepository {
private:
git_repository* repo;
public:
GitRepository(const std::string& path) {
git_libgit2_init();
if (git_repository_open(&repo, path.c_str()) != 0) {
const git_error* err = giterr_last();
std::cerr << "Error al abrir repositorio: " << err->message << std::endl;
throw std::runtime_error("Error al abrir repositorio Git");
}
}
~GitRepository() {
git_repository_free(repo);
git_libgit2_shutdown();
}
void get_status() {
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED |
GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX |
GIT_STATUS_OPT_SORT_CASE_SENSITIVELY;
git_status_list* status_list;
if (git_status_list_new(&status_list, repo, &opts) != 0) {
const git_error* err = giterr_last();
std::cerr << "Error al obtener estado: " << err->message << std::endl;
return;
}
size_t count = git_status_list_entrycount(status_list);
std::cout << "Estado del repositorio (" << count << " cambios):" << std::endl;
for (size_t i = 0; i < count; ++i) {
const git_status_entry* entry = git_status_byindex(status_list, i);
if (entry->status == GIT_STATUS_CURRENT) continue;
std::string status_str;
if (entry->status & GIT_STATUS_INDEX_NEW) status_str += "A";
if (entry->status & GIT_STATUS_INDEX_MODIFIED) status_str += "M";
if (entry->status & GIT_STATUS_INDEX_DELETED) status_str += "D";
if (entry->status & GIT_STATUS_INDEX_RENAMED) status_str += "R";
if (entry->status & GIT_STATUS_INDEX_TYPECHANGE) status_str += "T";
status_str += " | ";
if (entry->status & GIT_STATUS_WT_NEW) status_str += "A";
if (entry->status & GIT_STATUS_WT_MODIFIED) status_str += "M";
if (entry->status & GIT_STATUS_WT_DELETED) status_str += "D";
if (entry->status & GIT_STATUS_WT_RENAMED) status_str += "R";
if (entry->status & GIT_STATUS_WT_TYPECHANGE) status_str += "T";
if (entry->status & GIT_STATUS_WT_UNREADABLE) status_str += "?";
if (entry->status & GIT_STATUS_IGNORED) status_str += "I";
if (entry->status & GIT_STATUS_CONFLICTED) status_str += "C";
const char* old_path = entry->head_to_index->old_file.path;
const char* new_path = entry->head_to_index->new_file.path;
const char* wt_path = entry->index_to_workdir->old_file.path;
std::cout << status_str << " " << (old_path ? old_path :
new_path ? new_path :
wt_path ? wt_path : "???") << std::endl;
}
git_status_list_free(status_list);
}
};
int main() {
try {
GitRepository repo(".");
repo.get_status();
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
sudo apt install libgit2-dev
Y luego compilar con:
g++ -std=c++17 git_integration.cpp -lgit2 -o git_integration
Ejemplo de conexión y consultas a MySQL:
#include <iostream>
#include <mysql/mysql.h>
class MySQLConnection {
private:
MYSQL* conn;
public:
MySQLConnection(const std::string& host, const std::string& user,
const std::string& pass, const std::string& db) {
conn = mysql_init(nullptr);
if (!conn) {
throw std::runtime_error("Error al inicializar MySQL");
}
if (!mysql_real_connect(conn, host.c_str(), user.c_str(), pass.c_str(),
db.c_str(), 0, nullptr, 0)) {
std::string err = mysql_error(conn);
mysql_close(conn);
throw std::runtime_error("Error al conectar a MySQL: " + err);
}
}
~MySQLConnection() {
mysql_close(conn);
}
void executeQuery(const std::string& query) {
if (mysql_query(conn, query.c_str())) {
throw std::runtime_error("Error en la consulta: " + std::string(mysql_error(conn)));
}
MYSQL_RES* result = mysql_store_result(conn);
if (!result) {
if (mysql_field_count(conn) == 0) {
// No hay resultados (INSERT, UPDATE, DELETE, etc.)
std::cout << "Filas afectadas: " << mysql_affected_rows(conn) << std::endl;
return;
} else {
throw std::runtime_error("Error al obtener resultados: " +
std::string(mysql_error(conn)));
}
}
// Mostrar resultados
MYSQL_ROW row;
MYSQL_FIELD* fields = mysql_fetch_fields(result);
int num_fields = mysql_num_fields(result);
// Encabezados de columnas
for (int i = 0; i < num_fields; i++) {
std::cout << fields[i].name << "\t";
}
std::cout << std::endl;
// Filas de datos
while ((row = mysql_fetch_row(result))) {
for (int i = 0; i < num_fields; i++) {
std::cout << (row[i] ? row[i] : "NULL") << "\t";
}
std::cout << std::endl;
}
mysql_free_result(result);
}
};
int main() {
try {
// Configuración de conexión
std::string host = "localhost";
std::string user = "usuario";
std::string pass = "contraseña";
std::string db = "basedatos";
MySQLConnection conn(host, user, pass, db);
// Crear tabla
conn.executeQuery("CREATE TABLE IF NOT EXISTS empleados ("
"id INT AUTO_INCREMENT PRIMARY KEY, "
"nombre VARCHAR(50) NOT NULL, "
"departamento VARCHAR(50), "
"salario DECIMAL(10,2))");
// Insertar datos
conn.executeQuery("INSERT INTO empleados (nombre, departamento, salario) VALUES "
"('Juan Pérez', 'TI', 4500.00), "
"('Ana Gómez', 'RH', 3800.00), "
"('Carlos Ruiz', 'TI', 5200.00)");
// Consultar datos
std::cout << "\nEmpleados en TI:" << std::endl;
conn.executeQuery("SELECT nombre, salario FROM empleados WHERE departamento = 'TI'");
// Actualizar datos
conn.executeQuery("UPDATE empleados SET salario = salario * 1.1 WHERE departamento = 'TI'");
// Verificar actualización
std::cout << "\nEmpleados en TI después del aumento:" << std::endl;
conn.executeQuery("SELECT nombre, salario FROM empleados WHERE departamento = 'TI'");
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
sudo apt install libmysqlclient-dev
Y luego compilar con:
g++ -std=c++17 mysql_example.cpp -lmysqlclient -o mysql_example
Conexión y operaciones básicas con MongoDB:
#include <iostream>
#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>
#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/json.hpp>
using namespace mongocxx;
using bsoncxx::builder::stream::document;
using bsoncxx::builder::stream::open_document;
using bsoncxx::builder::stream::close_document;
using bsoncxx::builder::stream::finalize;
class MongoDBClient {
private:
instance instance{}; // Debe mantenerse durante toda la aplicación
client conn;
database db;
public:
MongoDBClient(const std::string& uri, const std::string& db_name)
: conn{uri::create(uri)}, db{conn[db_name]} {}
void insert_document(const std::string& collection_name, const std::string& json) {
auto collection = db[collection_name];
auto doc = bsoncxx::from_json(json);
collection.insert_one(doc.view());
}
void find_documents(const std::string& collection_name, const std::string& query_json = "{}") {
auto collection = db[collection_name];
auto query = bsoncxx::from_json(query_json);
auto cursor = collection.find(query.view());
std::cout << "Documentos encontrados:" << std::endl;
for(auto&& doc : cursor) {
std::cout << bsoncxx::to_json(doc) << std::endl;
}
}
};
int main() {
try {
MongoDBClient mongo("mongodb://localhost:27017", "empresaDB");
// Insertar documentos
mongo.insert_document("empleados", R"({
"nombre": "Ana García",
"departamento": "TI",
"skills": ["C++", "Linux", "MongoDB"],
"salario": 5200.00,
"fecha_ingreso": { "$date": "2020-05-15T00:00:00Z" }
})");
mongo.insert_document("empleados", R"({
"nombre": "Carlos Méndez",
"departamento": "DevOps",
"skills": ["Docker", "Kubernetes", "AWS"],
"salario": 5800.00,
"fecha_ingreso": { "$date": "2019-11-20T00:00:00Z" }
})");
// Consultar documentos
std::cout << "\nTodos los empleados:" << std::endl;
mongo.find_documents("empleados");
std::cout << "\nEmpleados de TI:" << std::endl;
mongo.find_documents("empleados", R"({"departamento": "TI"})");
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
sudo apt install libmongocxx-dev libbsoncxx-dev
Compilar con:
g++ -std=c++17 mongodb_example.cpp -lmongocxx -lbsoncxx -o mongodb_example
Ejemplo de uso de Redis como base de datos clave-valor:
#include <iostream>
#include <hiredis/hiredis.h>
class RedisClient {
private:
redisContext* conn;
public:
RedisClient(const std::string& host, int port) {
conn = redisConnect(host.c_str(), port);
if (conn == nullptr || conn->err) {
if (conn) {
throw std::runtime_error("Error de conexión: " + std::string(conn->errstr));
} else {
throw std::runtime_error("Error al asignar contexto Redis");
}
}
}
~RedisClient() {
redisFree(conn);
}
void set(const std::string& key, const std::string& value) {
redisReply* reply = (redisReply*)redisCommand(conn, "SET %s %s", key.c_str(), value.c_str());
if (reply == nullptr) {
throw std::runtime_error("Error en SET: " + std::string(conn->errstr));
}
freeReplyObject(reply);
}
std::string get(const std::string& key) {
redisReply* reply = (redisReply*)redisCommand(conn, "GET %s", key.c_str());
if (reply == nullptr) {
throw std::runtime_error("Error en GET: " + std::string(conn->errstr));
}
if (reply->type == REDIS_REPLY_NIL) {
freeReplyObject(reply);
return "";
}
std::string result = reply->str;
freeReplyObject(reply);
return result;
}
void publish(const std::string& channel, const std::string& message) {
redisReply* reply = (redisReply*)redisCommand(
conn, "PUBLISH %s %s", channel.c_str(), message.c_str());
if (reply == nullptr) {
throw std::runtime_error("Error en PUBLISH: " + std::string(conn->errstr));
}
freeReplyObject(reply);
}
};
int main() {
try {
RedisClient redis("localhost", 6379);
// Almacenamiento clave-valor
redis.set("servidor:nombre", "servidor_produccion");
redis.set("servidor:carga", "45%");
std::cout << "Nombre del servidor: " << redis.get("servidor:nombre") << std::endl;
std::cout << "Carga del servidor: " << redis.get("servidor:carga") << std::endl;
// Pub/Sub
redis.publish("canal_monitoreo", "Alerta: Servidor sobrecargado");
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
Ejemplo básico de un módulo del kernel (en C, llamado desde C++):
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Tu Nombre");
MODULE_DESCRIPTION("Un módulo simple del kernel");
static int __init hello_init(void) {
printk(KERN_INFO "Hola Kernel!\n");
return 0;
}
static void __exit hello_exit(void) {
printk(KERN_INFO "Adiós Kernel\n");
}
module_init(hello_init);
module_exit(hello_exit);
obj-m := hello_kernel.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
Ejemplo de cómo interactuar con módulos del kernel:
#include <iostream>
#include <fstream>
#include <string>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
class KernelInterface {
private:
int fd;
public:
KernelInterface(const std::string& device_path) {
fd = open(device_path.c_str(), O_RDWR);
if (fd < 0) {
throw std::runtime_error("No se pudo abrir el dispositivo");
}
}
~KernelInterface() {
if (fd >= 0) close(fd);
}
std::string read_kernel_message() {
char buffer[1024];
ssize_t bytes_read = read(fd, buffer, sizeof(buffer)-1);
if (bytes_read < 0) {
throw std::runtime_error("Error al leer del dispositivo");
}
buffer[bytes_read] = '\0';
return std::string(buffer);
}
void write_to_kernel(const std::string& message) {
if (write(fd, message.c_str(), message.size()) < 0) {
throw std::runtime_error("Error al escribir al dispositivo");
}
}
void ioctl_command(unsigned long command, void* data = nullptr) {
if (ioctl(fd, command, data) < 0) {
throw std::runtime_error("Error en ioctl");
}
}
};
int main() {
try {
// Ejemplo con /proc/kmsg (necesita permisos)
KernelInterface kmsg("/proc/kmsg");
std::cout << "Mensaje del kernel: " << kmsg.read_kernel_message() << std::endl;
// Ejemplo con un dispositivo ficticio /dev/mi_dispositivo
KernelInterface dev("/dev/mi_dispositivo");
dev.write_to_kernel("Hola desde espacio de usuario");
std::cout << "Respuesta: " << dev.read_kernel_message() << std::endl;
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
Ejemplo de un driver simple (en C, llamado desde C++):
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#define DEVICE_NAME "mi_driver"
#define BUFFER_SIZE 1024
static int major;
static char msg_buffer[BUFFER_SIZE];
static int msg_size;
static int device_open(struct inode *inode, struct file *file) {
printk(KERN_INFO "Dispositivo abierto\n");
return 0;
}
static int device_release(struct inode *inode, struct file *file) {
printk(KERN_INFO "Dispositivo cerrado\n");
return 0;
}
static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset) {
int bytes_read = 0;
if (*offset >= msg_size) return 0;
if (*offset + length > msg_size)
length = msg_size - *offset;
if (copy_to_user(buffer, msg_buffer + *offset, length))
return -EFAULT;
*offset += length;
return length;
}
static ssize_t device_write(struct file *filp, const char *buffer, size_t length, loff_t *offset) {
if (length > BUFFER_SIZE) length = BUFFER_SIZE;
if (copy_from_user(msg_buffer, buffer, length))
return -EFAULT;
msg_size = length;
return length;
}
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
static int __init mi_driver_init(void) {
major = register_chrdev(0, DEVICE_NAME, &fops);
if (major < 0) {
printk(KERN_ALERT "Error al registrar el driver\n");
return major;
}
printk(KERN_INFO "Driver registrado con major number %d\n", major);
return 0;
}
static void __exit mi_driver_exit(void) {
unregister_chrdev(major, DEVICE_NAME);
printk(KERN_INFO "Driver desregistrado\n");
}
module_init(mi_driver_init);
module_exit(mi_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Tu Nombre");
MODULE_DESCRIPTION("Un driver de caracteres simple");
#include <iostream>
#include <fstream>
#include <string>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
class DeviceDriver {
private:
int fd;
std::string device_path;
public:
DeviceDriver(const std::string& path) : device_path(path) {
fd = open(device_path.c_str(), O_RDWR);
if (fd < 0) {
throw std::runtime_error("No se pudo abrir el dispositivo " + device_path);
}
}
~DeviceDriver() {
if (fd >= 0) close(fd);
}
std::string read_from_device() {
char buffer[1024];
ssize_t bytes_read = read(fd, buffer, sizeof(buffer)-1);
if (bytes_read < 0) {
throw std::runtime_error("Error al leer del dispositivo");
}
buffer[bytes_read] = '\0';
return std::string(buffer);
}
void write_to_device(const std::string& data) {
if (write(fd, data.c_str(), data.size()) < 0) {
throw std::runtime_error("Error al escribir al dispositivo");
}
}
void test_driver() {
std::string test_msg = "Mensaje de prueba para el driver";
std::cout << "Escribiendo en el dispositivo: " << test_msg << std::endl;
write_to_device(test_msg);
std::cout << "Leyendo del dispositivo:" << std::endl;
std::cout << read_from_device() << std::endl;
}
};
int main() {
try {
// Necesitas crear el nodo del dispositivo primero:
// mknod /dev/mi_driver c 250 0 (usando el major number correcto)
DeviceDriver driver("/dev/mi_driver");
driver.test_driver();
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
#include <iostream>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <cstring>
class SerialPort {
private:
int fd;
std::string port;
public:
SerialPort(const std::string& port_name) : port(port_name), fd(-1) {}
~SerialPort() {
if (is_open()) close();
}
bool is_open() const { return fd >= 0; }
bool open_port(int baud_rate = B9600) {
fd = open(port.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
if (fd < 0) return false;
struct termios options;
tcgetattr(fd, &options);
// Configuración básica
cfsetispeed(&options, baud_rate);
cfsetospeed(&options, baud_rate);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_oflag &= ~OPOST;
options.c_cc[VMIN] = 1; // Bloquear hasta que llegue al menos 1 byte
options.c_cc[VTIME] = 0; // Sin timeout
if (tcsetattr(fd, TCSANOW, &options) < 0) {
close();
return false;
}
return true;
}
void close() {
if (is_open()) {
::close(fd);
fd = -1;
}
}
ssize_t write_data(const std::string& data) {
if (!is_open()) return -1;
return write(fd, data.c_str(), data.size());
}
std::string read_data(size_t max_length = 256) {
if (!is_open()) return "";
char buffer[max_length + 1];
ssize_t bytes_read = read(fd, buffer, max_length);
if (bytes_read < 0) return "";
buffer[bytes_read] = '\0';
return std::string(buffer);
}
};
int main() {
SerialPort serial("/dev/ttyS0"); // Cambiar por el puerto correcto
if (!serial.open_port()) {
std::cerr << "Error al abrir el puerto serial" << std::endl;
return 1;
}
std::cout << "Puerto serial abierto. Enviando datos..." << std::endl;
// Enviar comando AT básico
serial.write_data("AT\r\n");
// Esperar respuesta
usleep(100000); // 100ms de espera
std::string response = serial.read_data();
std::cout << "Respuesta: " << response << std::endl;
serial.close();
return 0;
}
#include <iostream>
#include <vector>
#include <cstdint>
#include "serial_port.h" // Usar la clase SerialPort anterior
class ModbusRTU {
private:
SerialPort port;
uint16_t calculate_crc(const std::vector<uint8_t>& data) {
uint16_t crc = 0xFFFF;
for (uint8_t byte : data) {
crc ^= byte;
for (int i = 0; i < 8; i++) {
if (crc & 0x0001) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
public:
ModbusRTU(const std::string& port_name) : port(port_name) {}
bool connect(int baud_rate = 19200) {
return port.open_port(baud_rate);
}
std::vector<uint16_t> read_holding_registers(uint8_t slave_id,
uint16_t start_addr,
uint16_t reg_count) {
std::vector<uint8_t> request = {
slave_id, // Dirección del esclavo
0x03, // Función: Leer registros de holding
(uint8_t)(start_addr >> 8),
(uint8_t)(start_addr & 0xFF),
(uint8_t)(reg_count >> 8),
(uint8_t)(reg_count & 0xFF)
};
// Calcular CRC
uint16_t crc = calculate_crc(request);
request.push_back(crc & 0xFF);
request.push_back(crc >> 8);
// Enviar solicitud
port.write_data(std::string(request.begin(), request.end()));
// Leer respuesta (ajustar según timeout esperado)
usleep(200000); // 200ms
std::string response_str = port.read_data(256);
std::vector<uint8_t> response(response_str.begin(), response_str.end());
// Verificar CRC
if (response.size() < 2) return {};
uint16_t received_crc = (response[response.size()-1] << 8) |
response[response.size()-2];
uint16_t calculated_crc = calculate_crc(
std::vector<uint8_t>(response.begin(), response.end()-2));
if (received_crc != calculated_crc) {
std::cerr << "Error de CRC" << std::endl;
return {};
}
// Procesar datos
std::vector<uint16_t> registers;
for (size_t i = 3; i < response.size()-2; i += 2) {
registers.push_back((response[i] << 8) | response[i+1]);
}
return registers;
}
};
int main() {
ModbusRTU modbus("/dev/ttyUSB0");
if (!modbus.connect()) {
std::cerr << "Error al conectar con el dispositivo Modbus" << std::endl;
return 1;
}
// Leer 2 registros de holding empezando en la dirección 0
auto registers = modbus.read_holding_registers(1, 0, 2);
if (!registers.empty()) {
std::cout << "Registros leídos:" << std::endl;
for (size_t i = 0; i < registers.size(); ++i) {
std::cout << "Registro " << i << ": " << registers[i] << std::endl;
}
} else {
std::cerr << "Error al leer registros" << std::endl;
}
return 0;
}
#include <iostream>
#include <string>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
class AESEncryptor {
private:
AES_KEY encrypt_key;
AES_KEY decrypt_key;
unsigned char iv[AES_BLOCK_SIZE];
public:
AESEncryptor(const std::string& key) {
if (key.size() != 16 && key.size() != 24 && key.size() != 32) {
throw std::runtime_error("La clave debe ser de 128, 192 o 256 bits");
}
// Configurar claves de encriptación y desencriptación
AES_set_encrypt_key((const unsigned char*)key.c_str(), key.size()*8, &encrypt_key);
AES_set_decrypt_key((const unsigned char*)key.c_str(), key.size()*8, &decrypt_key);
// Generar IV aleatorio
if (RAND_bytes(iv, AES_BLOCK_SIZE) != 1) {
throw std::runtime_error("Error al generar IV");
}
}
std::string encrypt(const std::string& plaintext) {
// Asegurar que el texto plano sea múltiplo del tamaño de bloque
size_t padded_size = ((plaintext.size() + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
std::vector<unsigned char> padded(padded_size);
memcpy(padded.data(), plaintext.data(), plaintext.size());
// Buffer para el texto cifrado
std::vector<unsigned char> ciphertext(padded_size);
// Realizar la encriptación
AES_cbc_encrypt(padded.data(), ciphertext.data(), padded_size,
&encrypt_key, iv, AES_ENCRYPT);
// Devolver el texto cifrado como string (incluyendo el IV al principio)
std::string result(iv, iv + AES_BLOCK_SIZE);
result.append(ciphertext.begin(), ciphertext.end());
return result;
}
std::string decrypt(const std::string& ciphertext) {
if (ciphertext.size() <= AES_BLOCK_SIZE || (ciphertext.size() % AES_BLOCK_SIZE) != 0) {
throw std::runtime_error("Texto cifrado inválido");
}
// Extraer el IV (primeros 16 bytes)
unsigned char local_iv[AES_BLOCK_SIZE];
memcpy(local_iv, ciphertext.data(), AES_BLOCK_SIZE);
// Obtener el texto cifrado real
const unsigned char* actual_ciphertext =
(const unsigned char*)ciphertext.data() + AES_BLOCK_SIZE;
size_t ciphertext_size = ciphertext.size() - AES_BLOCK_SIZE;
// Buffer para el texto plano
std::vector<unsigned char> plaintext(ciphertext_size);
// Realizar la desencriptación
AES_cbc_encrypt(actual_ciphertext, plaintext.data(), ciphertext_size,
&decrypt_key, local_iv, AES_DECRYPT);
// Eliminar padding y devolver como string
return std::string(plaintext.begin(), plaintext.end());
}
};
int main() {
try {
// Clave AES-256 (32 bytes)
std::string key = "mi_clave_secreta_de_32_bytes_123456";
AESEncryptor aes(key);
std::string plaintext = "Este es un mensaje secreto para encriptar con AES";
std::cout << "Texto original: " << plaintext << std::endl;
// Encriptar
std::string ciphertext = aes.encrypt(plaintext);
std::cout << "Texto encriptado (base64): " << base64_encode(ciphertext) << std::endl;
// Desencriptar
std::string decrypted = aes.decrypt(ciphertext);
std::cout << "Texto desencriptado: " << decrypted << std::endl;
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
#include <iostream>
#include <string>
#include <openssl/sha.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/err.h>
class CryptoUtils {
public:
static std::string sha256_hash(const std::string& input) {
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, input.c_str(), input.size());
SHA256_Final(hash, &sha256);
return std::string(hash, hash + SHA256_DIGEST_LENGTH);
}
static void generate_self_signed_cert(const std::string& cert_path,
const std::string& key_path) {
RSA* rsa = RSA_generate_key(2048, RSA_F4, nullptr, nullptr);
if (!rsa) {
throw std::runtime_error("Error al generar clave RSA");
}
X509* x509 = X509_new();
if (!x509) {
RSA_free(rsa);
throw std::runtime_error("Error al crear certificado X509");
}
// Configurar versión y número de serie
X509_set_version(x509, 2);
ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
// Configurar validez (1 año)
X509_gmtime_adj(X509_get_notBefore(x509), 0);
X509_gmtime_adj(X509_get_notAfter(x509), 31536000L);
// Configurar clave pública
X509_set_pubkey(x509, EVP_PKEY_new());
EVP_PKEY_set1_RSA(X509_get_pubkey(x509), rsa);
// Configurar nombre
X509_NAME* name = X509_get_subject_name(x509);
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC,
(const unsigned char*)"US", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
(const unsigned char*)"Mi Empresa", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
(const unsigned char*)"localhost", -1, -1, 0);
// El emisor es el mismo que el sujeto (autofirmado)
X509_set_issuer_name(x509, name);
// Firmar el certificado
if (!X509_sign(x509, EVP_PKEY_new(), EVP_sha256())) {
X509_free(x509);
RSA_free(rsa);
throw std::runtime_error("Error al firmar certificado");
}
// Guardar clave privada
FILE* key_file = fopen(key_path.c_str(), "wb");
if (!key_file) {
X509_free(x509);
RSA_free(rsa);
throw std::runtime_error("Error al abrir archivo de clave");
}
PEM_write_RSAPrivateKey(key_file, rsa, nullptr, nullptr, 0, nullptr, nullptr);
fclose(key_file);
// Guardar certificado
FILE* cert_file = fopen(cert_path.c_str(), "wb");
if (!cert_file) {
X509_free(x509);
RSA_free(rsa);
throw std::runtime_error("Error al abrir archivo de certificado");
}
PEM_write_X509(cert_file, x509);
fclose(cert_file);
// Liberar memoria
X509_free(x509);
RSA_free(rsa);
}
};
int main() {
try {
// Ejemplo de hash SHA-256
std::string password = "mi_contraseña_secreta";
std::string hash = CryptoUtils::sha256_hash(password);
std::cout << "SHA-256 de '" << password << "': ";
for (unsigned char c : hash) {
printf("%02x", c);
}
std::cout << std::endl;
// Generar certificado autofirmado
CryptoUtils::generate_self_signed_cert("certificado.pem", "clave_privada.pem");
std::cout << "Certificado y clave generados con éxito" << std::endl;
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <atomic>
#include <condition_variable>
#include <queue>
#include <functional>
class ThreadPool {
private:
std::vector<std::thread> workers;
std::queue<std::function<void()>> tasks;
std::mutex queue_mutex;
std::condition_variable condition;
std::atomic<bool> stop;
public:
ThreadPool(size_t threads) : stop(false) {
for (size_t i = 0; i < threads; ++i) {
workers.emplace_back([this] {
while (true) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(this->queue_mutex);
this->condition.wait(lock, [this] {
return this->stop || !this->tasks.empty();
});
if (this->stop && this->tasks.empty())
return;
task = std::move(this->tasks.front());
this->tasks.pop();
}
task();
}
});
}
}
template<class F>
void enqueue(F&& f) {
{
std::unique_lock<std::mutex> lock(queue_mutex);
tasks.emplace(std::forward<F>(f));
}
condition.notify_one();
}
~ThreadPool() {
stop = true;
condition.notify_all();
for (std::thread &worker : workers) {
worker.join();
}
}
};
int main() {
ThreadPool pool(4);
std::mutex cout_mutex;
for (int i = 0; i < 8; ++i) {
pool.enqueue([i, &cout_mutex] {
{
std::lock_guard<std::mutex> lock(cout_mutex);
std::cout << "Tarea " << i << " ejecutada por el hilo "
<< std::this_thread::get_id() << std::endl;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
});
}
// Esperar a que todas las tareas terminen
std::this_thread::sleep_for(std::chrono::seconds(3));
return 0;
}
cmake_minimum_required(VERSION 3.12)
project(AdvancedCppProject LANGUAGES CXX)
# Configuración estándar
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Opciones de configuración
option(BUILD_TESTS "Build tests" ON)
option(BUILD_BENCHMARKS "Build benchmarks" OFF)
option(ENABLE_COVERAGE "Enable code coverage" OFF)
option(USE_SANITIZERS "Enable sanitizers" ON)
# Configuraciones de compilación
add_compile_options(
-Wall
-Wextra
-Werror
-pedantic
-Wconversion
-Wsign-conversion
)
# Configuración para cobertura
if(ENABLE_COVERAGE)
add_compile_options(--coverage -O0 -g)
add_link_options(--coverage)
endif()
# Configuración de sanitizers
if(USE_SANITIZERS)
add_compile_options(
-fsanitize=address
-fsanitize=undefined
-fno-omit-frame-pointer
)
add_link_options(
-fsanitize=address
-fsanitize=undefined
)
endif()
# Configuración de subdirectorios
add_subdirectory(src)
# Pruebas unitarias
if(BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
# Benchmarks
if(BUILD_BENCHMARKS)
add_subdirectory(benchmarks)
endif()
# Instalación
install(TARGETS advanced_cpp_app DESTINATION bin)
install(DIRECTORY include/ DESTINATION include)