summaryrefslogtreecommitdiff
path: root/lib/ypc.h
blob: 2885ab4b35f6237638bb27525903f71ee37e6d94 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#ifndef YPC_H_
#define YPC_H_

#ifdef YPC_INTERNAL_H_
#define YPC_IMPORT YPC_EXPORT
#elif defined(_WIN32) || defined(__CYGWIN__)
#define YPC_IMPORT __declspec(dllimport)
#else
#define YPC_IMPORT
#endif

#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

typedef struct ypc ypc;
typedef struct ypc_msg ypc_msg;
typedef struct ypc_serv ypc_serv;


typedef struct {
    uint8_t *buf;
    uint32_t size, len;
} ypc_val;

typedef struct {
    const uint8_t *buf;
} ypc_get;

typedef struct {
    const uint8_t *buf;
} ypc_iter;

typedef enum {
    YPC_NULL,
    YPC_BOOL,
    YPC_INT,
    YPC_FLOAT,
    YPC_BIN,
    YPC_TEXT,
    YPC_ARRAY,
    YPC_MAP,
    YPC_CLOSE
} ypc_type;


#define YPC_NONBLOCK  0x01
#define YPC_RECV      0x02
#define YPC_CANREAD   0x04
#define YPC_CANWRITE  0x08
#define YPC_COPY      0x10


#define YPC_EPROTOCOL      -10 /* Received an invalid message */
#define YPC_ECONNREFUSED    -9 /* Connection refused */
#define YPC_EINVAL          -8 /* Invalid argument */
#define YPC_EADDR           -7 /* Invalid or unrecognized address */
#define YPC_EPERM           -6 /* Not enough permissions */
#define YPC_EDISCONNECT     -5 /* Remote end disconnected */
#define YPC_EADDRINUSE      -4 /* Address already in use */
#define YPC_ENOSUPPORT      -3 /* Protocol/operation not supported */
#define YPC_ENOMEM          -2 /* Out of memory */
#define YPC_EFAIL           -1 /* Generic fail code, for when no specific error is available or useful */


/* I don't like having this struct part of the public ABI, but it is the kind
 * of struct one might want to embed. Let's just pray that 4x32bit will suffice
 * for eternity. */
typedef struct {
    uint32_t len;
    uint32_t bitmap;
    uint32_t depth : 6;
    uint32_t state : 3;
    bool wantval   : 1;
    uint8_t utf8state;
    uint32_t pad;
} ypc_val_parser;


#ifdef __cplusplus
extern "C" {
#endif

YPC_IMPORT int ypc_init();

YPC_IMPORT void ypc_val_parse_init(ypc_val_parser *);
YPC_IMPORT int ypc_val_parse(ypc_val_parser *, const uint8_t *, size_t *);
YPC_IMPORT int ypc_val_resize(ypc_val *, size_t);
YPC_IMPORT int ypc_add_raw(ypc_val *, const uint8_t *, size_t);
YPC_IMPORT int ypc_add_int(ypc_val *, int64_t);
YPC_IMPORT int ypc_add_float(ypc_val *, double);
YPC_IMPORT int ypc_add_bin(ypc_val *, const uint8_t *, size_t);
YPC_IMPORT int ypc_add_textn(ypc_val *, const char *, size_t);
YPC_IMPORT int64_t ypc_get_int(ypc_get);
YPC_IMPORT double ypc_get_float(ypc_get);
YPC_IMPORT size_t ypc_get_size(ypc_get);

YPC_IMPORT ypc_msg *ypc_msg_new(const char *, size_t);
YPC_IMPORT void ypc_msg_free(ypc_msg *);

YPC_IMPORT int ypc_connect(ypc **, const char *);
YPC_IMPORT int ypc_process(ypc *, uint32_t);
YPC_IMPORT bool ypc_want_write(ypc *);
YPC_IMPORT int ypc_fd(ypc *);
YPC_IMPORT int ypc_send(ypc *, ypc_msg *, uint32_t);
YPC_IMPORT ypc_msg *ypc_recv(ypc *);
YPC_IMPORT void ypc_free(ypc *);

YPC_IMPORT int ypc_serv_unix(ypc_serv **, const char *);
YPC_IMPORT int ypc_serv_tcp(ypc_serv **, const char *);
YPC_IMPORT int ypc_serv_keypair(char *, size_t, char *, size_t);
YPC_IMPORT int ypc_serv_tcps(ypc_serv **, const char *, const char *, const char *);
YPC_IMPORT int ypc_serv_accept(ypc_serv *, ypc **, uint32_t);
YPC_IMPORT int ypc_serv_fd(ypc_serv *);
YPC_IMPORT void ypc_serv_free(ypc_serv *);

#ifdef __cplusplus
}
#endif


/* Smallish stuff that is better suited for inlining */
static inline int ypc_val_init(ypc_val *v, size_t size)   { v->buf = NULL; v->len = 0; return ypc_val_resize(v, size ? size : 512); }
static inline void ypc_val_free(ypc_val *v)               { free(v->buf); }
static inline int ypc_add_null(ypc_val *v)                { return ypc_add_raw(v, (const uint8_t *)"\0", 1); }
static inline int ypc_add_bool(ypc_val *v, bool b)        { return ypc_add_raw(v, (const uint8_t *)(b ? "\2" : "\1"), 1); }
static inline int ypc_add_text(ypc_val *v, const char *t) { return ypc_add_textn(v, t, strlen(t)); }
static inline int ypc_add_array(ypc_val *v)               { return ypc_add_raw(v, (const uint8_t *)"\12", 1); }
static inline int ypc_add_map(ypc_val *v)                 { return ypc_add_raw(v, (const uint8_t *)"\13", 1); }
static inline int ypc_add_close(ypc_val *v)               { return ypc_add_raw(v, (const uint8_t *)"\14", 1); }
static inline int ypc_add_val(ypc_val *v, ypc_get g)      { return ypc_add_raw(v, g.buf, ypc_get_size(g)); }

static inline ypc_get        ypc_val_get(ypc_val *v)    { ypc_get g = {v->buf}; return g; }
static inline bool           ypc_get_bool(ypc_get g)    { return *g.buf == 2; }
static inline const char *   ypc_get_text(ypc_get g)    { return (const char *)g.buf+1; }
static inline const uint8_t *ypc_get_bin(ypc_get g)     { return g.buf+4; }
static inline size_t         ypc_get_bin_len(ypc_get g) { return (g.buf[1] << 16) | (g.buf[2] << 8) | g.buf[3]; }
static inline ypc_iter       ypc_get_iter(ypc_get g)    { ypc_iter i = {g.buf+1}; return i; }
static inline bool           ypc_iter_end(ypc_iter i)   { return *i.buf == 12; }
static inline ypc_get        ypc_iter_next(ypc_iter *i) { ypc_get g = {i->buf}; i->buf += ypc_get_size(g); return g; }

/* While not very small, this is still a static inline to enable a bunch of
 * optimizations. E.g. ypc_get_type(v) == YPC_TEXT should compile down to
 * *v->buf == 9, which is much cheaper than a function call. A similar
 * optimization is possible when using ypc_get_type() in a switch statement.
 */
static inline ypc_type ypc_get_type(ypc_get v) {
    switch(*v.buf) {
    case 0:
        return YPC_NULL;
    case 1:
    case 2:
        return YPC_BOOL;
    case 3:
    case 4:
    case 5:
    case 6:
        return YPC_INT;
    case 7:
        return YPC_FLOAT;
    case 8:
        return YPC_BIN;
    case 9:
        return YPC_TEXT;
    case 10:
        return YPC_ARRAY;
    case 11:
        return YPC_MAP;
    case 12:
        return YPC_CLOSE;
    }
    return 0; /* Should not happen... */
}

#endif