text: /**
   * Copyright (c) 2020 Paul-Louis Ageneau
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
  #ifndef JUICE_SERVER_H
  #define JUICE_SERVER_H
  
  #ifndef NO_SERVER
  
  #ifdef __STDC_NO_ATOMICS__
  #define NO_ATOMICS
  #endif
  
  #include "addr.h"
  #include "juice.h"
  #include "socket.h"
  #include "stun.h"
  #include "thread.h"
  #include "timestamp.h"
  #include "turn.h"
  
  #include <stdbool.h>
  #include <stdint.h>
  
  #define SERVER_DEFAULT_REALM "libjuice"
  #define SERVER_DEFAULT_MAX_ALLOCATIONS 1024
  #define SERVER_DEFAULT_MAX_PEERS 16
  
  #define SERVER_NONCE_KEY_SIZE 32
  
  // RFC 8656: The server [...] SHOULD expire the nonce at least once every hour during the lifetime
  // of the allocation
  #define SERVER_NONCE_KEY_LIFETIME 600 * 1000 // 10 min
  
  typedef enum server_turn_alloc_state {
  	SERVER_TURN_ALLOC_EMPTY,
  	SERVER_TURN_ALLOC_DELETED,
  	SERVER_TURN_ALLOC_FULL
  } server_turn_alloc_state_t;
  
  typedef struct server_turn_alloc {
  	server_turn_alloc_state_t state;
  	addr_record_t record;
  	juice_server_credentials_t *credentials;
  	uint8_t transaction_id[STUN_TRANSACTION_ID_SIZE];
  	timestamp_t timestamp;
  	socket_t sock;
  	turn_map_t map;
  } server_turn_alloc_t;
  
  typedef struct juice_server {
  	juice_server_config_t config;
  	uint8_t **credentials_userhash;
  	uint8_t nonce_key[SERVER_NONCE_KEY_SIZE];
  	timestamp_t nonce_key_timestamp;
  	socket_t sock;
  	thread_t thread;
  	mutex_t mutex;
  	bool thread_stopped;
  	server_turn_alloc_t *allocs;
  	int allocs_count;
  } juice_server_t;
  
  juice_server_t *server_create(const juice_server_config_t *config);
  void server_do_destroy(juice_server_t *server);
  void server_destroy(juice_server_t *server);
  
  uint16_t server_get_port(juice_server_t *server);
  
  void server_run(juice_server_t *server);
  int server_send(juice_server_t *agent, const addr_record_t *dst, const char *data, size_t size);
  int server_stun_send(juice_server_t *server, const addr_record_t *dst, const stun_message_t *msg,
                       const char *password // password may be NULL
  );
  int server_recv(juice_server_t *server);
  int server_forward(juice_server_t *server, server_turn_alloc_t *alloc);
  int server_input(juice_server_t *agent, char *buf, size_t len, const addr_record_t *src);
  int server_interrupt(juice_server_t *server);
  int server_bookkeeping(juice_server_t *agent, timestamp_t *next_timestamp);
  
  void server_get_nonce(juice_server_t *server, const addr_record_t *src, char *nonce);
  void server_prepare_credentials(juice_server_t *server, const addr_record_t *src,
                                  const juice_server_credentials_t *credentials, stun_message_t *msg);
  
  int server_dispatch_stun(juice_server_t *server, void *buf, size_t size, stun_message_t *msg,
                           const addr_record_t *src);
  int server_answer_stun_binding(juice_server_t *server, const uint8_t *transaction_id,
                                 const addr_record_t *src);
  int server_answer_stun_error(juice_server_t *server, const uint8_t *transaction_id,
                               const addr_record_t *src, stun_method_t method, unsigned int code,
                               const juice_server_credentials_t *credentials);
  
  int server_process_turn_allocate(juice_server_t *server, const stun_message_t *msg,
                                   const addr_record_t *src, juice_server_credentials_t *credentials);
  int server_process_turn_create_permission(juice_server_t *server, const stun_message_t *msg,
                                            const addr_record_t *src,
                                            const juice_server_credentials_t *credentials);
  int server_process_turn_channel_bind(juice_server_t *server, const stun_message_t *msg,
                                       const addr_record_t *src,
                                       const juice_server_credentials_t *credentials);
  int server_process_turn_send(juice_server_t *server, const stun_message_t *msg,
                               const addr_record_t *src);
  int server_process_channel_data(juice_server_t *server, char *buf, size_t len,
                                  const addr_record_t *src);
  
  #endif // ifndef NO_SERVER
  
  #endif
  