/* 
 * File:   server_udp.c
 * Author: Arthur Brandao
 *
 * Created on 14 novembre 2018
 */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "error.h"
#include "server.h"

/* --- Extern --- */
extern int serrno;

/* --- Fonctions privées --- */
boolean server_bind(Server this, int port) {
    /* Declaration variable */
    int tmp;

    /* Bind */
    this->serv.sin_family = AF_INET;
    this->serv.sin_port = htons(port);
    this->serv.sin_addr.s_addr = htonl(INADDR_ANY);
    tmp = bind(this->socket, (struct sockaddr*) &this->serv, sizeof (struct sockaddr_in));
    if (tmp == ERR) {
        free(this);
        serrno = SEBIND;
        addperror("Impossible de bind la socket");
        return false;
    }
    
    return true;
}

ssize_t server_receive_udp(Server this, char* buf, size_t size) {
    /* Declaration variable */
    int tmp;

    /* Reception */
    memset(buf, 0, size);
    tmp = recvfrom(this->socket, buf, size, 0, (struct sockaddr*) &this->client, &this->addr);
    if (tmp == ERR) {
        serrno = SERECEIVE;
        addperror("Impossible de récupèrer les données");
        return ERR;
    }

    /* Retour */
    return tmp;
}

boolean server_send_udp(Server this, char* msg) {
    /* Declaration variable */
    int tmp;

    /* Envoi */
    tmp = sendto(this->socket, msg, strlen(msg) * sizeof (char), 0, (struct sockaddr*) &this->client, sizeof (struct sockaddr_in));
    if (tmp == ERR) {
        serrno = SESEND;
        addperror("Impossible d'envoyer les données");
        return false;
    }
    
    return true;
}

/* --- Fonctions publiques --- */
Server server_create_udp() {
    /* Declaration variable */
    Server this;

    /* Creation socket */
    this = malloc(sizeof (struct server));
    this->socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (this->socket == ERR) {
        free(this);
        serrno = SESOCKET;
        addperror("Impossible de créer la socket");
        return NULL;
    }
    this->addr = sizeof (struct sockaddr_in);
    memset(&this->serv, 0, sizeof (struct sockaddr_in));

    /* Lien fonctions */
    this->server_bind = server_bind;
    this->server_receive = server_receive_udp;
    this->server_send = server_send_udp;
    this->server_accept = NULL;

    /* Type de serveur */
    this->type = SERV_UDP;

    /* Retour */
    return this;
}

void server_close(Server this) {
    /* Ferme */
    if (close(this->socket) == ERR) {
        serrno = SECLOSE;
        addperror("Impossible de fermer la socket");
    }

    /* Supprime */
    free(this);
}
