summaryrefslogtreecommitdiffstats
path: root/rpc/rpc-lib/src/rpcsvc.h
blob: a51edc73698ea2e9a17eb5996d50352d78b4d075 (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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
/*
  Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
  This file is part of GlusterFS.

  This file is licensed to you under your choice of the GNU Lesser
  General Public License, version 3 or any later version (LGPLv3 or
  later), or the GNU General Public License, version 2 (GPLv2), in all
  cases as published by the Free Software Foundation.
*/

#ifndef _RPCSVC_H
#define _RPCSVC_H

#include <glusterfs/gf-event.h>
#include "rpc-transport.h"
#include <glusterfs/logging.h>
#include <glusterfs/dict.h>
#include <glusterfs/mem-pool.h>
#include <glusterfs/list.h>
#include <glusterfs/iobuf.h>
#include "xdr-rpc.h"
#include <glusterfs/glusterfs.h>
#include <glusterfs/xlator.h>
#include "rpcsvc-common.h"

#include <pthread.h>
#include <sys/uio.h>
#include <inttypes.h>
#include <rpc/rpc_msg.h>
#include <glusterfs/compat.h>

#ifndef MAX_IOVEC
#define MAX_IOVEC 16
#endif

/* TODO: we should store prognums at a centralized location to avoid conflict
         or use a robust random number generator to avoid conflicts
*/

#define RPCSVC_INFRA_PROGRAM 7712846 /* random number */

typedef enum {
    RPCSVC_PROC_EVENT_THREAD_DEATH = 0,
} rpcsvc_infra_procnum_t;

#define RPCSVC_DEFAULT_OUTSTANDING_RPC_LIMIT                                   \
    64 /* Default for protocol/server */
#define RPCSVC_DEF_NFS_OUTSTANDING_RPC_LIMIT 16 /* Default for nfs/server */
#define RPCSVC_MAX_OUTSTANDING_RPC_LIMIT 65536
#define RPCSVC_MIN_OUTSTANDING_RPC_LIMIT 0 /* No limit i.e. Unlimited */

#define GF_RPCSVC "rpc-service"
#define RPCSVC_THREAD_STACK_SIZE ((size_t)(1024 * GF_UNIT_KB))

#define RPCSVC_FRAGHDR_SIZE 4 /* 4-byte RPC fragment header size */
#define RPCSVC_DEFAULT_LISTEN_PORT GF_DEFAULT_BASE_PORT
#define RPCSVC_DEFAULT_MEMFACTOR 8
#define RPCSVC_EVENTPOOL_SIZE_MULT 1024
#define RPCSVC_POOLCOUNT_MULT 64
#define RPCSVC_CONN_READ (128 * GF_UNIT_KB)
#define RPCSVC_PAGE_SIZE (128 * GF_UNIT_KB)
#define RPC_ROOT_UID 0
#define RPC_ROOT_GID 0
#define RPC_NOBODY_UID 65534
#define RPC_NOBODY_GID 65534

/* RPC Record States */
#define RPCSVC_READ_FRAGHDR 1
#define RPCSVC_READ_FRAG 2
/* The size in bytes, if crossed by a fragment will be handed over to the
 * vectored actor so that it can allocate its buffers the way it wants.
 * In our RPC layer, we assume that vectored RPC requests/records are never
 * spread over multiple RPC fragments since that prevents us from determining
 * whether the record should be handled in RPC layer completely or handed to
 * the vectored handler.
 */
#define RPCSVC_VECTORED_FRAGSZ 4096
#define RPCSVC_VECTOR_READCRED 1003
#define RPCSVC_VECTOR_READVERFSZ 1004
#define RPCSVC_VECTOR_READVERF 1005
#define RPCSVC_VECTOR_IGNORE 1006
#define RPCSVC_VECTOR_READVEC 1007
#define RPCSVC_VECTOR_READPROCHDR 1008

#define rpcsvc_record_vectored_baremsg(rs)                                     \
    (((rs)->state == RPCSVC_READ_FRAG) && (rs)->vecstate == 0)
#define rpcsvc_record_vectored_cred(rs)                                        \
    ((rs)->vecstate == RPCSVC_VECTOR_READCRED)
#define rpcsvc_record_vectored_verfsz(rs)                                      \
    ((rs)->vecstate == RPCSVC_VECTOR_READVERFSZ)
#define rpcsvc_record_vectored_verfread(rs)                                    \
    ((rs)->vecstate == RPCSVC_VECTOR_READVERF)
#define rpcsvc_record_vectored_ignore(rs)                                      \
    ((rs)->vecstate == RPCSVC_VECTOR_IGNORE)
#define rpcsvc_record_vectored_readvec(rs)                                     \
    ((rs)->vecstate == RPCSVC_VECTOR_READVEC)
#define rpcsvc_record_vectored_readprochdr(rs)                                 \
    ((rs)->vecstate == RPCSVC_VECTOR_READPROCHDR)
#define rpcsvc_record_vectored(rs) ((rs)->fragsize > RPCSVC_VECTORED_FRAGSZ)
/* Includes bytes up to and including the credential length field. The credlen
 * will be followed by @credlen bytes of credential data which will have to be
 * read separately by the vectored reader. After the credentials comes the
 * verifier which will also have to be read separately including the 8 bytes of
 * verf flavour and verflen.
 */
#define RPCSVC_BARERPC_MSGSZ 32
#define rpcsvc_record_readfraghdr(rs) ((rs)->state == RPCSVC_READ_FRAGHDR)
#define rpcsvc_record_readfrag(rs) ((rs)->state == RPCSVC_READ_FRAG)

#define RPCSVC_LOWVERS 2
#define RPCSVC_HIGHVERS 2

#if 0
#error "defined in /usr/include/rpc/auth.h"

#define AUTH_NONE 0 /* no authentication */
#define AUTH_NULL 0 /* backward compatibility */
#define AUTH_SYS 1  /* unix style (uid, gids) */
#define AUTH_UNIX AUTH_SYS
#define AUTH_SHORT 2     /* short hand unix style */
#define AUTH_DES 3       /* des style (encrypted timestamps) */
#define AUTH_DH AUTH_DES /* Diffie-Hellman (this is DES) */
#define AUTH_KERB 4      /* kerberos style */
#endif                   /* */

typedef struct rpcsvc_program rpcsvc_program_t;

struct rpcsvc_notify_wrapper {
    struct list_head list;
    void *data;
    rpcsvc_notify_t notify;
};
typedef struct rpcsvc_notify_wrapper rpcsvc_notify_wrapper_t;

typedef struct rpcsvc_request rpcsvc_request_t;

typedef struct {
    rpc_transport_t *trans;
    rpcsvc_t *svc;
    /* FIXME: remove address from this structure. Instead use get_myaddr
     * interface implemented by individual transports.
     */
    struct sockaddr_storage sa;
    struct list_head list;
} rpcsvc_listener_t;

struct rpcsvc_config {
    int max_block_size;
};

typedef struct rpcsvc_auth_data {
    int flavour;
    int datalen;
    char authdata[GF_MAX_AUTH_BYTES];
} rpcsvc_auth_data_t;

#define rpcsvc_auth_flavour(au) ((au).flavour)

typedef struct drc_client drc_client_t;
typedef struct drc_cached_op drc_cached_op_t;

/* The container for the RPC call handed up to an actor.
 * Dynamically allocated. Lives till the call reply is completely
 * transmitted.
 * */
struct rpcsvc_request {
    /* connection over which this request came. */
    rpc_transport_t *trans;

    rpcsvc_t *svc;

    rpcsvc_program_t *prog;

    int prognum;

    int progver;

    int procnum;

    int type;

    /* Uid and gid filled by the rpc-auth module during the authentication
     * phase.
     */
    uid_t uid;
    gid_t gid;
    pid_t pid;

    gf_lkowner_t lk_owner;
    uint64_t gfs_id;

    /* Might want to move this to AUTH_UNIX specific state since this array
     * is not available for every authentication scheme.
     */
    gid_t *auxgids;
    gid_t auxgidsmall[SMALL_GROUP_COUNT];
    gid_t *auxgidlarge;
    int auxgidcount;

    /* The RPC message payload, contains the data required
     * by the program actors. This is the buffer that will need to
     * be de-xdred by the actor.
     */
    struct iovec msg[MAX_IOVEC];
    int count;

    struct iobref *iobref;

    /* Status of the RPC call, whether it was accepted or denied. */
    int rpc_status;

    /* In case, the call was denied, the RPC error is stored here
     * till the reply is sent.
     */
    int rpc_err;

    /* In case the failure happened because of an authentication problem
     * , this value needs to be assigned the correct auth error number.
     */
    int auth_err;

    /* There can be cases of RPC requests where the reply needs to
     * be built from multiple sources. E.g. where even the NFS reply
     * can contain a payload, as in the NFSv3 read reply. Here the RPC header
     * ,NFS header and the read data are brought together separately from
     * different buffers, so we need to stage the buffers temporarily here
     * before all of them get added to the connection's transmission list.
     */
    struct list_head txlist;

    /* While the reply record is being built, this variable keeps track
     * of how many bytes have been added to the record.
     */
    size_t payloadsize;

    /* The credentials extracted from the rpc request */
    rpcsvc_auth_data_t cred;

    /* The verified extracted from the rpc request. In request side
     * processing this contains the verifier sent by the client, on reply
     * side processing, it is filled with the verified that will be
     * sent to the client.
     */
    rpcsvc_auth_data_t verf;
    /* Container for a RPC program wanting to store a temp
     * request-specific item.
     */
    void *private;

    /* Container for transport to store request-specific item */
    void *trans_private;

    /* pointer to cached reply for use in DRC */
    drc_cached_op_t *reply;

    /* request queue in rpcsvc */
    struct list_head request_list;

    /* Things passed to rpc layer from client */

    /* @flags: Can be used for binary data passed in xdata to be
       passed here instead */
    unsigned int flags;

    /* ctime: origin of time on the client side, ideally this is
       the one we should consider for time */
    struct timespec ctime;

    /* The identifier for the call from client.
     * Needed to pair the reply with the call.
     */
    uint32_t xid;

    /* Execute this request's actor function in ownthread of program?*/
    gf_boolean_t ownthread;

    gf_boolean_t synctask;
};

#define rpcsvc_request_program(req) ((rpcsvc_program_t *)((req)->prog))
#define rpcsvc_request_procnum(req) (((req)->procnum))
#define rpcsvc_request_program_private(req)                                    \
    (((rpcsvc_program_t *)((req)->prog))->private)
#define rpcsvc_request_accepted(req) ((req)->rpc_status == MSG_ACCEPTED)
#define rpcsvc_request_accepted_success(req) ((req)->rpc_err == SUCCESS)
#define rpcsvc_request_prog_minauth(req) (rpcsvc_request_program(req)->min_auth)
#define rpcsvc_request_cred_flavour(req) (rpcsvc_auth_flavour(req->cred))
#define rpcsvc_request_verf_flavour(req) (rpcsvc_auth_flavour(req->verf))
#define rpcsvc_request_service(req) ((req)->svc)
#define rpcsvc_request_uid(req) ((req)->uid)
#define rpcsvc_request_gid(req) ((req)->gid)
#define rpcsvc_request_private(req) ((req)->private)
#define rpcsvc_request_xid(req) ((req)->xid)
#define rpcsvc_request_set_private(req, prv) (req)->private = (void *)(prv)
#define rpcsvc_request_iobref_ref(req) (iobref_ref((req)->iobref))
#define rpcsvc_request_record_ref(req) (iobuf_ref((req)->recordiob))
#define rpcsvc_request_record_unref(req) (iobuf_unref((req)->recordiob))
#define rpcsvc_request_record_iob(req) ((req)->recordiob)
#define rpcsvc_request_set_vecstate(req, state) ((req)->vecstate = state)
#define rpcsvc_request_vecstate(req) ((req)->vecstate)
#define rpcsvc_request_transport(req) ((req)->trans)
#define rpcsvc_request_transport_ref(req) (rpc_transport_ref((req)->trans))
#define RPC_AUTH_ROOT_SQUASH(req)                                              \
    do {                                                                       \
        int gidcount = 0;                                                      \
        if (req->svc->root_squash) {                                           \
            if (req->uid == RPC_ROOT_UID)                                      \
                req->uid = req->svc->anonuid;                                  \
            if (req->gid == RPC_ROOT_GID)                                      \
                req->gid = req->svc->anongid;                                  \
                                                                               \
            for (gidcount = 0; gidcount < req->auxgidcount; ++gidcount) {      \
                if (!req->auxgids[gidcount])                                   \
                    req->auxgids[gidcount] = req->svc->anongid;                \
            }                                                                  \
        }                                                                      \
    } while (0);

#define RPC_AUTH_ALL_SQUASH(req)                                               \
    do {                                                                       \
        int gidcount = 0;                                                      \
        if (req->svc->all_squash) {                                            \
            req->uid = req->svc->anonuid;                                      \
            req->gid = req->svc->anongid;                                      \
                                                                               \
            for (gidcount = 0; gidcount < req->auxgidcount; ++gidcount) {      \
                if (!req->auxgids[gidcount])                                   \
                    req->auxgids[gidcount] = req->svc->anongid;                \
            }                                                                  \
        }                                                                      \
    } while (0);

#define RPCSVC_ACTOR_SUCCESS 0
#define RPCSVC_ACTOR_ERROR (-1)
#define RPCSVC_ACTOR_IGNORE (-2)

/* Functor for every type of protocol actor
 * must be defined like this.
 *
 * See the request structure for info on how to handle the request
 * in the program actor.
 *
 * On successful santify checks inside the actor, it should return
 * RPCSVC_ACTOR_SUCCESS.
 * On an error, on which the RPC layer is expected to return a reply, the actor
 * should return RPCSVC_ACTOR_ERROR.
 *
 */
typedef int (*rpcsvc_actor)(rpcsvc_request_t *req);
typedef int (*rpcsvc_vector_sizer)(int state, ssize_t *readsize,
                                   char *base_addr, char *curr_addr);

/* Every protocol actor will also need to specify the function the RPC layer
 * will use to serialize or encode the message into XDR format just before
 * transmitting on the connection.
 */
typedef void *(*rpcsvc_encode_reply)(void *msg);

/* Once the reply has been transmitted, the message will have to be de-allocated
 * , so every actor will need to provide a function that deallocates the message
 * it had allocated as a response.
 */
typedef void (*rpcsvc_deallocate_reply)(void *msg);

#define RPCSVC_NAME_MAX 32
/* The descriptor for each procedure/actor that runs
 * over the RPC service.
 */
typedef struct rpcsvc_actor_desc {
    char procname[RPCSVC_NAME_MAX];
    int procnum;
    rpcsvc_actor actor;

    /* Handler for cases where the RPC requests fragments are large enough
     * to benefit from being decoded into aligned memory addresses. While
     * decoding the request in a non-vectored manner, due to the nature of
     * the XDR scheme, RPC cannot guarantee memory aligned addresses for
     * the resulting message-specific structures. Allowing a specialized
     * handler for letting the RPC program read the data from the network
     * directly into its aligned buffers.
     */
    rpcsvc_vector_sizer vector_sizer;

    /* Can actor be ran on behalf an unprivileged requestor? */
    gf_boolean_t unprivileged;
    drc_op_type_t op_type;
} rpcsvc_actor_t;

typedef struct rpcsvc_request_queue {
    int gen;
    struct list_head request_queue;
    pthread_mutex_t queue_lock;
    pthread_cond_t queue_cond;
    pthread_t thread;
    struct rpcsvc_program *program;
    gf_boolean_t waiting;
} rpcsvc_request_queue_t;

/* Describes a program and its version along with the function pointers
 * required to handle the procedures/actors of each program/version.
 * Never changed ever by any thread so no need for a lock.
 */
struct rpcsvc_program {
    char progname[RPCSVC_NAME_MAX];
    int prognum;
    int progver;
    /* FIXME */
    dict_t *options; /* An opaque dictionary
                      * populated by the program
                      * (probably from xl->options)
                      * which contain enough
                      * information for transport to
                      * initialize. As a part of
                      * cleanup, the members of
                      * options which are of interest
                      * to transport should be put
                      * into a structure for better
                      * readability and structure
                      * should replace options member
                      * here.
                      */
#if 0
        int                     progaddrfamily; /* AF_INET or AF_INET6 */
        char                    *proghost;      /* Bind host, can be NULL */
#endif
    rpcsvc_actor_t *actors; /* All procedure handlers */
    int numactors;          /* Num actors in actor array */
    int proghighvers;       /* Highest ver for program
                               supported by the system. */
    int proglowvers;        /* Lowest ver */

    /* Program specific state handed to actors */
    void *private;

    /* This upcall is provided by the program during registration.
     * It is used to notify the program about events like connection being
     * destroyed etc. The rpc program may take appropriate actions, for eg.,
     * in the case of connection being destroyed, it should cleanup its
     * state stored in the connection.
     */
    rpcsvc_notify_t notify;

    /* An integer that identifies the min auth strength that is required
     * by this protocol, for eg. MOUNT3 needs AUTH_UNIX at least.
     * See RFC 1813, Section 5.2.1.
     */
    int min_auth;

    /* list member to link to list of registered services with rpcsvc */
    struct list_head program;
    rpcsvc_request_queue_t request_queue[EVENT_MAX_THREADS];
    char request_queue_status[EVENT_MAX_THREADS / 8 + 1];
    pthread_mutex_t thr_lock;
    pthread_cond_t thr_cond;
    int threadcount;
    int thr_queue;
    pthread_key_t req_queue_key;

    /* eventthreadcount is just a readonly copy of the actual value
     * owned by the event sub-system
     * It is used to control the scaling of rpcsvc_request_handler threads
     */
    int eventthreadcount;
    uint16_t progport; /* Registered with portmap */
    /* Execute actor function in program's own thread? This will reduce */
    /* the workload on poller threads */
    gf_boolean_t ownthread;
    gf_boolean_t alive;

    gf_boolean_t synctask;
};

typedef struct rpcsvc_cbk_program {
    char *progname;
    int prognum;
    int progver;
} rpcsvc_cbk_program_t;
/* All users of RPC services should use this API to register their
 * procedure handlers.
 */
extern int
rpcsvc_program_register(rpcsvc_t *svc, rpcsvc_program_t *program,
                        gf_boolean_t add_to_head);

extern int
rpcsvc_program_unregister(rpcsvc_t *svc, rpcsvc_program_t *program);

/* This will create and add a listener to listener pool. Programs can
 * use any of the listener in this pool. A single listener can be used by
 * multiple programs and vice versa. There can also be a one to one mapping
 * between a program and a listener. After registering a program with rpcsvc,
 * the program has to be associated with a listener using
 * rpcsvc_program_register_portmap.
 */
/* FIXME: can multiple programs registered on same port? */
extern int32_t
rpcsvc_create_listeners(rpcsvc_t *svc, dict_t *options, char *name);

void
rpcsvc_listener_destroy(rpcsvc_listener_t *listener);

extern int
rpcsvc_program_register_portmap(rpcsvc_program_t *newprog, uint32_t port);

#ifdef IPV6_DEFAULT
extern int
rpcsvc_program_register_rpcbind6(rpcsvc_program_t *newprog, uint32_t port);
extern int
rpcsvc_program_unregister_rpcbind6(rpcsvc_program_t *newprog);
#endif

extern int
rpcsvc_program_unregister_portmap(rpcsvc_program_t *newprog);

extern int
rpcsvc_register_portmap_enabled(rpcsvc_t *svc);

/* Inits the global RPC service data structures.
 * Called in main.
 */
extern rpcsvc_t *
rpcsvc_init(xlator_t *xl, glusterfs_ctx_t *ctx, dict_t *options,
            uint32_t poolcount);

extern int
rpcsvc_reconfigure_options(rpcsvc_t *svc, dict_t *options);

int
rpcsvc_register_notify(rpcsvc_t *svc, rpcsvc_notify_t notify, void *mydata);

/* unregister a notification callback @notify with data @mydata from svc.
 * returns the number of notification callbacks unregistered.
 */
int
rpcsvc_unregister_notify(rpcsvc_t *svc, rpcsvc_notify_t notify, void *mydata);

int
rpcsvc_transport_submit(rpc_transport_t *trans, struct iovec *rpchdr,
                        int rpchdrcount, struct iovec *proghdr,
                        int proghdrcount, struct iovec *progpayload,
                        int progpayloadcount, struct iobref *iobref,
                        void *priv);

int
rpcsvc_submit_message(rpcsvc_request_t *req, struct iovec *proghdr,
                      int hdrcount, struct iovec *payload, int payloadcount,
                      struct iobref *iobref);

int
rpcsvc_submit_generic(rpcsvc_request_t *req, struct iovec *proghdr,
                      int hdrcount, struct iovec *payload, int payloadcount,
                      struct iobref *iobref);

extern int
rpcsvc_error_reply(rpcsvc_request_t *req);

#define RPCSVC_PEER_STRLEN 1024
#define RPCSVC_AUTH_ACCEPT 1
#define RPCSVC_AUTH_REJECT 2
#define RPCSVC_AUTH_DONTCARE 3

extern int
rpcsvc_transport_peername(rpc_transport_t *trans, char *hostname, int hostlen);

extern int
rpcsvc_transport_peeraddr(rpc_transport_t *trans, char *addrstr, int addrlen,
                          struct sockaddr_storage *returnsa, socklen_t sasize);

extern int
rpcsvc_auth_check(rpcsvc_t *svc, char *volname, char *ipaddr);

extern int
rpcsvc_transport_privport_check(rpcsvc_t *svc, char *volname, uint16_t port);

#define rpcsvc_request_seterr(req, err) ((req)->rpc_err = (int)(err))
#define rpcsvc_request_set_autherr(req, err) ((req)->auth_err = (int)(err))

extern int
rpcsvc_submit_vectors(rpcsvc_request_t *req);

extern int
rpcsvc_request_attach_vector(rpcsvc_request_t *req, struct iovec msgvec,
                             struct iobuf *iob, struct iobref *ioref,
                             int finalvector);

typedef int (*auth_init_trans)(rpc_transport_t *trans, void *priv);
typedef int (*auth_init_request)(rpcsvc_request_t *req, void *priv);
typedef int (*auth_request_authenticate)(rpcsvc_request_t *req, void *priv);

/* This structure needs to be registered by every authentication scheme.
 * Our authentication schemes are stored per connection because
 * each connection will end up using a different authentication scheme.
 */
typedef struct rpcsvc_auth_ops {
    auth_init_trans transport_init;
    auth_init_request request_init;
    auth_request_authenticate authenticate;
} rpcsvc_auth_ops_t;

typedef struct rpcsvc_auth_flavour_desc {
    char authname[RPCSVC_NAME_MAX];
    int authnum;
    rpcsvc_auth_ops_t *authops;
    void *authprivate;
} rpcsvc_auth_t;

typedef void *(*rpcsvc_auth_initer_t)(rpcsvc_t *svc, dict_t *options);

struct rpcsvc_auth_list {
    struct list_head authlist;
    rpcsvc_auth_initer_t init;
    /* Should be the name with which we identify the auth scheme given
     * in the volfile options.
     * This should be different from the authname in rpc_auth_t
     * in way that makes it easier to specify this scheme in the volfile.
     * This is because the technical names of the schemes can be a bit
     * arcane.
     */
    char name[RPCSVC_NAME_MAX];
    rpcsvc_auth_t *auth;
    int enable;
};

extern int
rpcsvc_auth_request_init(rpcsvc_request_t *req, struct rpc_msg *callmsg);

extern int
rpcsvc_auth_init(rpcsvc_t *svc, dict_t *options);

extern int
rpcsvc_auth_reconf(rpcsvc_t *svc, dict_t *options);

extern int
rpcsvc_auth_transport_init(rpc_transport_t *xprt);

extern int
rpcsvc_authenticate(rpcsvc_request_t *req);

extern int
rpcsvc_auth_array(rpcsvc_t *svc, char *volname, int *autharr, int arrlen);

/* If the request has been sent using AUTH_UNIX, this function returns the
 * auxiliary gids as an array, otherwise, it returns NULL.
 * Move to auth-unix specific source file when we need to modularize the
 * authentication code even further to support mode auth schemes.
 */
extern gid_t *
rpcsvc_auth_unix_auxgids(rpcsvc_request_t *req, int *arrlen);

extern char *
rpcsvc_volume_allowed(dict_t *options, char *volname);

int
rpcsvc_request_submit(rpcsvc_t *rpc, rpc_transport_t *trans,
                      rpcsvc_cbk_program_t *prog, int procnum, void *req,
                      glusterfs_ctx_t *ctx, xdrproc_t xdrproc);

int
rpcsvc_callback_submit(rpcsvc_t *rpc, rpc_transport_t *trans,
                       rpcsvc_cbk_program_t *prog, int procnum,
                       struct iovec *proghdr, int proghdrcount,
                       struct iobref *iobref);

rpcsvc_actor_t *
rpcsvc_program_actor(rpcsvc_request_t *req);

int
rpcsvc_transport_unix_options_build(dict_t *options, char *filepath);
int
rpcsvc_set_allow_insecure(rpcsvc_t *svc, dict_t *options);
int
rpcsvc_set_addr_namelookup(rpcsvc_t *svc, dict_t *options);
int
rpcsvc_set_root_squash(rpcsvc_t *svc, dict_t *options);
int
rpcsvc_set_all_squash(rpcsvc_t *svc, dict_t *options);
int
rpcsvc_set_outstanding_rpc_limit(rpcsvc_t *svc, dict_t *options, int defvalue);

int
rpcsvc_set_throttle_on(rpcsvc_t *svc);

int
rpcsvc_set_throttle_off(rpcsvc_t *svc);

gf_boolean_t
rpcsvc_get_throttle(rpcsvc_t *svc);

int
rpcsvc_auth_array(rpcsvc_t *svc, char *volname, int *autharr, int arrlen);
rpcsvc_vector_sizer
rpcsvc_get_program_vector_sizer(rpcsvc_t *svc, uint32_t prognum,
                                uint32_t progver, int procnum);
void
rpcsvc_autoscale_threads(glusterfs_ctx_t *ctx, rpcsvc_t *rpc, int incr);

extern int
rpcsvc_destroy(rpcsvc_t *svc);
#endif