/*---------------------------------------------------------------------------*
  C HEADER  cf_socket_p.h

  Copyright (c) 2003-2006, James H. Woodyatt
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:

    Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

    Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in
    the documentation and/or other materials provided with the
    distribution

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  OF THE POSSIBILITY OF SUCH DAMAGE. 
 *---------------------------------------------------------------------------*/

#ifndef _CF_SOCKET_P_H
#define _CF_SOCKET_P_H

#include "cf_common_p.h"

#include <stddef.h>
#include <sys/types.h>
#include <sys/socket.h>

#define Cf_socket_sockaddrx_struct(suffix) \
struct cf_socket_sockaddrx_##suffix##_s { \
    size_t                      sx_socklen; \
    struct sockaddr_##suffix    sx_sockaddr_##suffix; \
}

#define Cf_socket_sockaddrx_t(suffix)   Cf_socket_sockaddrx_##suffix##_t

#define Cf_socket_sockaddrx_typedef(suffix) \
typedef struct cf_socket_sockaddrx_##suffix##_s Cf_socket_sockaddrx_t(suffix)

#define Cf_socket_sockaddrx_val(suffix, v) \
    ((Cf_socket_sockaddrx_t(suffix)*) Data_custom_val(v))

Cf_socket_sockaddrx_struct(storage);
Cf_socket_sockaddrx_typedef(storage);

struct cf_socket_sockaddrx_unit_s {
    size_t              sx_socklen;
    struct sockaddr     sx_sockaddr;
};

typedef struct cf_socket_sockaddrx_unit_s Cf_socket_sockaddrx_unit_t;

#define Cf_socket_sockaddrx_unit_val(v) \
    ((Cf_socket_sockaddrx_unit_t*) Data_custom_val(v))

typedef value (*Cf_socket_sockaddrx_cons_f)
   (const struct sockaddr* saPtr, size_t saLen);

struct cf_socket_domain_s {
    int				d_domain;	/* PF_INET, PF_LOCAL, ... */
    int				d_family;	/* AF_INET, AF_LOCAL, ... */
    Cf_socket_sockaddrx_cons_f	d_consaddr;	/* sockaddr alloc function */
    size_t			d_socklen;	/* sizeof(sockaddr_xxx) */
};

typedef struct cf_socket_domain_s Cf_socket_domain_t;

#define Cf_socket_domain_val(v)	((Cf_socket_domain_t*) Data_custom_val(v))
extern value cf_socket_domain_alloc(const Cf_socket_domain_t* ptr);

struct cf_socket_s {
    int			s_fd;
    int			s_socktype;
    int			s_protocol;
    Cf_socket_domain_t	s_domain;
};

typedef struct cf_socket_s Cf_socket_t;

#define Cf_socket_val(v)	((Cf_socket_t*) Data_custom_val(v))
extern value cf_socket_alloc
   (int fd, int socktype, int protocol, const Cf_socket_domain_t* domainPtr);

extern int cf_socket_msg_flags_to_int(value flagsVal);
extern value cf_socket_msg_flags_of_int(int flags);

struct cf_socket_option_context_s {
    int	xopt_fd;
    int	xopt_level;
    int	xopt_name;
};

typedef struct cf_socket_option_context_s Cf_socket_option_context_t;

typedef value (*Cf_socket_getsockopt_f)
   (const Cf_socket_option_context_t* contextPtr);
typedef void (*Cf_socket_setsockopt_f)
   (const Cf_socket_option_context_t* contextPtr, value x);

struct cf_socket_option_s {
    int                     opt_level;
    int                     opt_name;
    Cf_socket_getsockopt_f	opt_get;
    Cf_socket_setsockopt_f	opt_set;
    const char*             opt_name_str;
};

typedef struct cf_socket_option_s Cf_socket_option_t;

struct cf_socket_sockopt_lift_s {
    value                       ol_val;
    const Cf_socket_option_t	ol_option;
};

typedef struct cf_socket_sockopt_lift_s Cf_socket_sockopt_lift_t;

#define Cf_socket_option_val(v)	\
    ((const Cf_socket_option_t**) Data_custom_val(v))
extern value cf_socket_option_alloc(const Cf_socket_option_t* ptr);

extern void cf_socket_getsockopt_guard
   (const Cf_socket_option_context_t* contextPtr, void* optval,
    socklen_t* optlen);

extern void cf_socket_setsockopt_guard
   (const Cf_socket_option_context_t* contextPtr, const void* optval,
    socklen_t optlen);

extern value cf_socket_getsockopt_bool
   (const Cf_socket_option_context_t* contextPtr);

extern void cf_socket_setsockopt_bool
   (const Cf_socket_option_context_t* contextPtr, value x);

extern value cf_socket_getsockopt_int
   (const Cf_socket_option_context_t* contextPtr);

extern void cf_socket_setsockopt_int
   (const Cf_socket_option_context_t* contextPtr, value x);

extern value cf_socket_getsockopt_int_option
   (const Cf_socket_option_context_t* contextPtr);

extern void cf_socket_setsockopt_int_option
   (const Cf_socket_option_context_t* contextPtr, value x);

extern value cf_socket_getsockopt_float
   (const Cf_socket_option_context_t* contextPtr);

extern void cf_socket_setsockopt_float
   (const Cf_socket_option_context_t* contextPtr, value x);

#endif /* defined(_CF_SOCKET_P_H) */

/*--- End of File [ cf_socket_p.h ] ---*/
