Servidor intermedio en lenguaje C

Funcionalidades y características del servidor

Este servidor es modular y cuenta con las siguientes características clave:

  1. Manejo de múltiples solicitudes HTTP:
    • Soporta métodos GET, POST, PUT, PATCH, y DELETE, lo que permite procesar diferentes tipos de solicitudes para gestionar recursos.
    • Permite manejar solicitudes dinámicas con encabezados personalizados.
  2. Seguridad mediante HTTPS:
    • Utiliza OpenSSL para establecer conexiones seguras con SSL/TLS, cumpliendo con estándares internacionales como RFC 5246.
    • Protege la transferencia de datos entre el cliente y el servidor.
  3. Registro de eventos:
    • Guarda solicitudes y respuestas en un archivo de registro (server.log), lo que facilita la trazabilidad y el monitoreo.
  4. Autenticación básica:
    • Verifica solicitudes mediante encabezados HTTP de autorización (Authorization).
    • Permite un acceso controlado a través de credenciales (usuario y contraseña).
  5. Soporte para múltiples formatos:
    • Responde en formatos JSON, XML y HTML, adaptándose al encabezado Accept de las solicitudes HTTP.
    • Facilita la interoperabilidad con diferentes sistemas y aplicaciones.
  6. Modularidad:
    • Está estructurado en módulos independientes (request_handler, ssl_handler, auth, etc.), lo que facilita su mantenimiento y ampliación.

¿Se puede usar como backend y frontend?

Backend:

Sí, este servidor puede funcionar como un backend para gestionar contenido. Algunas de sus capacidades como backend incluyen:

  • Almacenar información desde el frontend:
    • Con los métodos POST, PUT, y PATCH, el servidor puede recibir datos del frontend y guardarlos en archivos, lo cual simula un sistema de almacenamiento.
    • Ejemplo: Al enviar un formulario desde el frontend, el servidor puede escribir los datos en un archivo.
  • Recuperar datos para el frontend:
    • Usando el método GET, el servidor puede devolver información previamente almacenada, permitiendo que el frontend muestre contenido dinámico.

Frontend:

Aunque el servidor puede enviar respuestas en formato HTML, no está diseñado para manejar tareas específicas de un frontend avanzado, como interfaces interactivas o dinámicas. Es posible usarlo para servir contenido estático, pero necesitarías herramientas complementarias como frameworks de JavaScript (React, Angular, etc.) para crear un frontend robusto.

¿Es escalable?

Este servidor tiene cierta capacidad de escalabilidad, pero hay consideraciones importantes:

  1. Escalabilidad horizontal:
    • Podrías ejecutar múltiples instancias del servidor en diferentes máquinas y usar un balanceador de carga para distribuir solicitudes.
  2. Limitaciones:
    • Manejo de datos: Actualmente, los datos se almacenan en archivos locales, lo cual no es óptimo para grandes volúmenes de información. Para escalar, deberías integrar bases de datos como MySQL, PostgreSQL, MongoDB, etc.
    • Manejo de clientes simultáneos: Aunque utiliza threads (hilos) para manejar clientes concurrentemente, la cantidad de clientes estará limitada por los recursos del sistema (CPU, memoria).
  3. Recomendaciones para escalabilidad:
    • Optimización de almacenamiento: Migrar de archivos locales a una base de datos.
    • Ampliación de seguridad: Implementar autenticación más avanzada (por ejemplo, OAuth2) y cifrado de datos sensible.
    • Integración con tecnologías modernas: Usar contenedores como Docker y herramientas de orquestación como Kubernetes para escalar el servidor de forma eficiente.

¿Es viable para proyectos reales?

Sí, con ciertas mejoras, este servidor puede ser usado como parte de un sistema real. Aquí tienes los puntos clave:

  • Proyectos pequeños: Ideal para aplicaciones educativas, prototipos o sistemas embebidos.
  • Proyectos grandes: Requiere escalabilidad, integración con bases de datos y autenticación más avanzada para funcionar como un backend completo en producción.
modular_server/
├── main.c
├── server.c
├── server.h
├── ssl_handler.c
├── ssl_handler.h
├── auth.c
├── auth.h
├── event_logger.c
├── event_logger.h
├── request_handler.c
├── request_handler.h
├── Makefile
├── server.crt    # Certificado SSL
├── server.key    # Llave privada SSL

 

 

 

 

 

request_handler.c

Este archivo implementa la lógica de manejo de solicitudes HTTP que serán procesadas por el servidor. 

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "request_handler.h"
#include "auth.h"
#include "event_logger.h"

// Tamaño máximo del buffer para solicitudes/respuestas
#define BUFFER_SIZE 4096

void handle_request(int client_socket, SSL_CTX *ctx) {
    char buffer[BUFFER_SIZE] = {0};
    SSL *ssl = SSL_new(ctx);
    SSL_set_fd(ssl, client_socket);

    if (SSL_accept(ssl) <= 0) {
        log_event("Error en el handshake SSL.");
        SSL_free(ssl);
        return;
    }

    SSL_read(ssl, buffer, BUFFER_SIZE);
    printf("Solicitud recibida:\n%s\n", buffer);

    // Registrar la solicitud
    log_event(buffer);

    // Analizar el encabezado de autorización
    char *auth_header = strstr(buffer, "Authorization: ");
    if (auth_header) {
        auth_header += strlen("Authorization: ");
        strtok(auth_header, "\r\n"); // Eliminar saltos de línea
        if (!authenticate_request(auth_header)) {
            const char *response = "HTTP/1.1 401 Unauthorized\r\nContent-Type: text/plain\r\n\r\nNo autorizado.";
            SSL_write(ssl, response, strlen(response));
            SSL_free(ssl);
            return;
        }
    } else {
        const char *response = "HTTP/1.1 401 Unauthorized\r\nContent-Type: text/plain\r\n\r\nNo autorizado.";
        SSL_write(ssl, response, strlen(response));
        SSL_free(ssl);
        return;
    }

    // Analizar la solicitud para manejar diferentes métodos HTTP
    if (strncmp(buffer, "GET", 3) == 0) {
        const char *response =
            "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nSolicitud GET manejada correctamente.\n";
        SSL_write(ssl, response, strlen(response));
    } else if (strncmp(buffer, "POST", 4) == 0) {
        const char *response =
            "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nSolicitud POST manejada correctamente.\n";
        SSL_write(ssl, response, strlen(response));
    } else if (strncmp(buffer, "PUT", 3) == 0) {
        const char *response =
            "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nSolicitud PUT manejada correctamente.\n";
        SSL_write(ssl, response, strlen(response));
    } else if (strncmp(buffer, "PATCH", 5) == 0) {
        const char *response =
            "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nSolicitud PATCH manejada correctamente.\n";
        SSL_write(ssl, response, strlen(response));
    } else if (strncmp(buffer, "DELETE", 6) == 0) {
        const char *response =
            "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nSolicitud DELETE manejada correctamente.\n";
        SSL_write(ssl, response, strlen(response));
    } else {
        const char *response =
            "HTTP/1.1 405 Method Not Allowed\r\nContent-Type: text/plain\r\n\r\nMétodo no permitido.";
        SSL_write(ssl, response, strlen(response));
    }

    // Liberar recursos de SSL
    SSL_free(ssl);
}

 

request_handler.h

Este archivo declara la función de manejo de solicitudes para que pueda usarse en otros módulos. 

#ifndef REQUEST_HANDLER_H
#define REQUEST_HANDLER_H

#include <openssl/ssl.h>

// Declaración de la función de manejo de solicitudes
void handle_request(int client_socket, SSL_CTX *ctx);

#endif

 

Makefile

CC = gcc
CFLAGS = -Wall -Wextra -I.
LIBS = -lssl -lcrypto

all: server

server: main.o server.o ssl_handler.o auth.o event_logger.o request_handler.o
    $(CC) -o server main.o server.o ssl_handler.o auth.o event_logger.o request_handler.o $(LIBS)

main.o: main.c server.h
    $(CC) $(CFLAGS) -c main.c

server.o: server.c server.h ssl_handler.h auth.h event_logger.h request_handler.h
    $(CC) $(CFLAGS) -c server.c

ssl_handler.o: ssl_handler.c ssl_handler.h
    $(CC) $(CFLAGS) -c ssl_handler.c

auth.o: auth.c auth.h
    $(CC) $(CFLAGS) -c auth.c

event_logger.o: event_logger.c event_logger.h
    $(CC) $(CFLAGS) -c event_logger.c

request_handler.o: request_handler.c request_handler.h
    $(CC) $(CFLAGS) -c request_handler.c

clean:
    rm -f *.o server

 

Generar certificados SSL

Si aún no tienes server.crt y server.key, crea un certificado SSL autofirmado:

openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt -days 365 -nodes 

Compilar el servidor

Desde la carpeta modular_server, ejecuta:  make   

Esto generará el ejecutable server.

make 

Ejecutar el servidor: 

./server 

Probar el servidor

Haz solicitudes al servidor usando herramientas como curl:

GET:

curl -X GET https://localhost:8080 -k
 

POST:

curl -X POST https://localhost:8080 -k
 

Con autenticación: 

curl -u usuario:contraseña https://localhost:8080 -k
 

Resumen

  • request_handler.c procesa solicitudes HTTP según el método (GET, POST, etc.).
  • request_handler.h declara las funciones necesarias para que el servidor utilice este módulo.
  • Makefile actualizado asegura que todos los módulos se compilen correctamente.

El servidor está completamente modularizado y funcional.

 

 

 

 

Destacado

Bootloader Avanzado en Ensamblador

Bootloader Avanzado en Ensamblador Características del Bootloader Se carga en la dirección 0x7C00 (BIOS). ...