155714Skris/* crypto/bio/bss_rtcp.c */
255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
355714Skris * All rights reserved.
455714Skris *
555714Skris * This package is an SSL implementation written
655714Skris * by Eric Young (eay@cryptsoft.com).
755714Skris * The implementation was written so as to conform with Netscapes SSL.
8296341Sdelphij *
955714Skris * This library is free for commercial and non-commercial use as long as
1055714Skris * the following conditions are aheared to.  The following conditions
1155714Skris * apply to all code found in this distribution, be it the RC4, RSA,
1255714Skris * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1355714Skris * included with this distribution is covered by the same copyright terms
1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15296341Sdelphij *
1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in
1755714Skris * the code are not to be removed.
1855714Skris * If this package is used in a product, Eric Young should be given attribution
1955714Skris * as the author of the parts of the library used.
2055714Skris * This can be in the form of a textual message at program startup or
2155714Skris * in documentation (online or textual) provided with the package.
22296341Sdelphij *
2355714Skris * Redistribution and use in source and binary forms, with or without
2455714Skris * modification, are permitted provided that the following conditions
2555714Skris * are met:
2655714Skris * 1. Redistributions of source code must retain the copyright
2755714Skris *    notice, this list of conditions and the following disclaimer.
2855714Skris * 2. Redistributions in binary form must reproduce the above copyright
2955714Skris *    notice, this list of conditions and the following disclaimer in the
3055714Skris *    documentation and/or other materials provided with the distribution.
3155714Skris * 3. All advertising materials mentioning features or use of this software
3255714Skris *    must display the following acknowledgement:
3355714Skris *    "This product includes cryptographic software written by
3455714Skris *     Eric Young (eay@cryptsoft.com)"
3555714Skris *    The word 'cryptographic' can be left out if the rouines from the library
3655714Skris *    being used are not cryptographic related :-).
37296341Sdelphij * 4. If you include any Windows specific code (or a derivative thereof) from
3855714Skris *    the apps directory (application code) you must include an acknowledgement:
3955714Skris *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40296341Sdelphij *
4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4455714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5155714Skris * SUCH DAMAGE.
52296341Sdelphij *
5355714Skris * The licence and distribution terms for any publically available version or
5455714Skris * derivative of this code cannot be changed.  i.e. this code cannot simply be
5555714Skris * copied and put under another distribution licence
5655714Skris * [including the GNU Public Licence.]
5755714Skris */
5855714Skris
59296341Sdelphij/*-
60296341Sdelphij * Written by David L. Jones <jonesd@kcgl1.eng.ohio-state.edu>
6155714Skris * Date:   22-JUL-1996
62296341Sdelphij * Revised: 25-SEP-1997         Update for 0.8.1, BIO_CTRL_SET -> BIO_C_SET_FD
6355714Skris */
6455714Skris/* VMS */
6555714Skris#include <stdio.h>
6655714Skris#include <stdlib.h>
6755714Skris#include <string.h>
6855714Skris#include <errno.h>
6955714Skris#include "cryptlib.h"
7055714Skris#include <openssl/bio.h>
7155714Skris
72296341Sdelphij#include <iodef.h>              /* VMS IO$_ definitions */
7355714Skris#include <starlet.h>
7455714Skris
7555714Skristypedef unsigned short io_channel;
7655714Skris/*************************************************************************/
77296341Sdelphijstruct io_status {
78296341Sdelphij    short status, count;
79296341Sdelphij    long flags;
80296341Sdelphij};
8155714Skris
82296341Sdelphij/* Should have member alignment inhibited */
83296341Sdelphijstruct rpc_msg {
84296341Sdelphij    /* 'A'-app data. 'R'-remote client 'G'-global */
85296341Sdelphij    char channel;
86296341Sdelphij    /* 'G'-get, 'P'-put, 'C'-confirm, 'X'-close */
87296341Sdelphij    char function;
88296341Sdelphij    /* Amount of data returned or max to return */
89296341Sdelphij    unsigned short int length;
90296341Sdelphij    /* variable data */
91296341Sdelphij    char data[4092];
9255714Skris};
9355714Skris#define RPC_HDR_SIZE (sizeof(struct rpc_msg) - 4092)
9455714Skris
9555714Skrisstruct rpc_ctx {
9655714Skris    int filled, pos;
9755714Skris    struct rpc_msg msg;
9855714Skris};
9955714Skris
100296341Sdelphijstatic int rtcp_write(BIO *h, const char *buf, int num);
101296341Sdelphijstatic int rtcp_read(BIO *h, char *buf, int size);
102296341Sdelphijstatic int rtcp_puts(BIO *h, const char *str);
103296341Sdelphijstatic int rtcp_gets(BIO *h, char *str, int size);
104296341Sdelphijstatic long rtcp_ctrl(BIO *h, int cmd, long arg1, void *arg2);
10555714Skrisstatic int rtcp_new(BIO *h);
10655714Skrisstatic int rtcp_free(BIO *data);
10755714Skris
108296341Sdelphijstatic BIO_METHOD rtcp_method = {
109296341Sdelphij    BIO_TYPE_FD,
110296341Sdelphij    "RTCP",
111296341Sdelphij    rtcp_write,
112296341Sdelphij    rtcp_read,
113296341Sdelphij    rtcp_puts,
114296341Sdelphij    rtcp_gets,
115296341Sdelphij    rtcp_ctrl,
116296341Sdelphij    rtcp_new,
117296341Sdelphij    rtcp_free,
118296341Sdelphij    NULL,
119296341Sdelphij};
12055714Skris
12155714SkrisBIO_METHOD *BIO_s_rtcp(void)
122296341Sdelphij{
123296341Sdelphij    return (&rtcp_method);
124296341Sdelphij}
125296341Sdelphij
12655714Skris/*****************************************************************************/
127296341Sdelphij/*
128296341Sdelphij * Decnet I/O routines.
12955714Skris */
13055714Skris
13155714Skris#ifdef __DECC
132296341Sdelphij# pragma message save
133296341Sdelphij# pragma message disable DOLLARID
13455714Skris#endif
13555714Skris
136296341Sdelphijstatic int get(io_channel chan, char *buffer, int maxlen, int *length)
13755714Skris{
13855714Skris    int status;
13955714Skris    struct io_status iosb;
140296341Sdelphij    status = sys$qiow(0, chan, IO$_READVBLK, &iosb, 0, 0,
141296341Sdelphij                      buffer, maxlen, 0, 0, 0, 0);
142296341Sdelphij    if ((status & 1) == 1)
143296341Sdelphij        status = iosb.status;
144296341Sdelphij    if ((status & 1) == 1)
145296341Sdelphij        *length = iosb.count;
14655714Skris    return status;
14755714Skris}
14855714Skris
149296341Sdelphijstatic int put(io_channel chan, char *buffer, int length)
15055714Skris{
15155714Skris    int status;
15255714Skris    struct io_status iosb;
153296341Sdelphij    status = sys$qiow(0, chan, IO$_WRITEVBLK, &iosb, 0, 0,
154296341Sdelphij                      buffer, length, 0, 0, 0, 0);
155296341Sdelphij    if ((status & 1) == 1)
156296341Sdelphij        status = iosb.status;
15755714Skris    return status;
15855714Skris}
15955714Skris
16055714Skris#ifdef __DECC
161296341Sdelphij# pragma message restore
16255714Skris#endif
16355714Skris
16455714Skris/***************************************************************************/
16555714Skris
16655714Skrisstatic int rtcp_new(BIO *bi)
16755714Skris{
16855714Skris    struct rpc_ctx *ctx;
169296341Sdelphij    bi->init = 1;
170296341Sdelphij    bi->num = 0;
171296341Sdelphij    bi->flags = 0;
172296341Sdelphij    bi->ptr = OPENSSL_malloc(sizeof(struct rpc_ctx));
173296341Sdelphij    ctx = (struct rpc_ctx *)bi->ptr;
174296341Sdelphij    ctx->filled = 0;
175296341Sdelphij    ctx->pos = 0;
176296341Sdelphij    return (1);
17755714Skris}
17855714Skris
17955714Skrisstatic int rtcp_free(BIO *a)
18055714Skris{
181296341Sdelphij    if (a == NULL)
182296341Sdelphij        return (0);
183296341Sdelphij    if (a->ptr)
184296341Sdelphij        OPENSSL_free(a->ptr);
185296341Sdelphij    a->ptr = NULL;
186296341Sdelphij    return (1);
18755714Skris}
188296341Sdelphij
18955714Skrisstatic int rtcp_read(BIO *b, char *out, int outl)
19055714Skris{
19155714Skris    int status, length;
19255714Skris    struct rpc_ctx *ctx;
19355714Skris    /*
19455714Skris     * read data, return existing.
19555714Skris     */
196296341Sdelphij    ctx = (struct rpc_ctx *)b->ptr;
197296341Sdelphij    if (ctx->pos < ctx->filled) {
198296341Sdelphij        length = ctx->filled - ctx->pos;
199296341Sdelphij        if (length > outl)
200296341Sdelphij            length = outl;
201296341Sdelphij        memmove(out, &ctx->msg.data[ctx->pos], length);
202296341Sdelphij        ctx->pos += length;
203296341Sdelphij        return length;
20455714Skris    }
20555714Skris    /*
20655714Skris     * Requst more data from R channel.
20755714Skris     */
20855714Skris    ctx->msg.channel = 'R';
20955714Skris    ctx->msg.function = 'G';
21055714Skris    ctx->msg.length = sizeof(ctx->msg.data);
211296341Sdelphij    status = put(b->num, (char *)&ctx->msg, RPC_HDR_SIZE);
212296341Sdelphij    if ((status & 1) == 0) {
213296341Sdelphij        return -1;
21455714Skris    }
21555714Skris    /*
21655714Skris     * Read.
21755714Skris     */
21855714Skris    ctx->pos = ctx->filled = 0;
219296341Sdelphij    status = get(b->num, (char *)&ctx->msg, sizeof(ctx->msg), &length);
220296341Sdelphij    if ((status & 1) == 0)
221296341Sdelphij        length = -1;
222296341Sdelphij    if (ctx->msg.channel != 'R' || ctx->msg.function != 'C') {
223296341Sdelphij        length = -1;
22455714Skris    }
22555714Skris    ctx->filled = length - RPC_HDR_SIZE;
226296341Sdelphij
227296341Sdelphij    if (ctx->pos < ctx->filled) {
228296341Sdelphij        length = ctx->filled - ctx->pos;
229296341Sdelphij        if (length > outl)
230296341Sdelphij            length = outl;
231296341Sdelphij        memmove(out, ctx->msg.data, length);
232296341Sdelphij        ctx->pos += length;
233296341Sdelphij        return length;
23455714Skris    }
23555714Skris
23655714Skris    return length;
23755714Skris}
23855714Skris
23968651Skrisstatic int rtcp_write(BIO *b, const char *in, int inl)
24055714Skris{
24155714Skris    int status, i, segment, length;
24255714Skris    struct rpc_ctx *ctx;
24355714Skris    /*
24455714Skris     * Output data, send in chunks no larger that sizeof(ctx->msg.data).
24555714Skris     */
246296341Sdelphij    ctx = (struct rpc_ctx *)b->ptr;
247296341Sdelphij    for (i = 0; i < inl; i += segment) {
248296341Sdelphij        segment = inl - i;
249296341Sdelphij        if (segment > sizeof(ctx->msg.data))
250296341Sdelphij            segment = sizeof(ctx->msg.data);
251296341Sdelphij        ctx->msg.channel = 'R';
252296341Sdelphij        ctx->msg.function = 'P';
253296341Sdelphij        ctx->msg.length = segment;
254296341Sdelphij        memmove(ctx->msg.data, &in[i], segment);
255296341Sdelphij        status = put(b->num, (char *)&ctx->msg, segment + RPC_HDR_SIZE);
256296341Sdelphij        if ((status & 1) == 0) {
257296341Sdelphij            i = -1;
258296341Sdelphij            break;
259296341Sdelphij        }
26055714Skris
261296341Sdelphij        status = get(b->num, (char *)&ctx->msg, sizeof(ctx->msg), &length);
262296341Sdelphij        if (((status & 1) == 0) || (length < RPC_HDR_SIZE)) {
263296341Sdelphij            i = -1;
264296341Sdelphij            break;
265296341Sdelphij        }
266296341Sdelphij        if ((ctx->msg.channel != 'R') || (ctx->msg.function != 'C')) {
267296341Sdelphij            printf("unexpected response when confirming put %c %c\n",
268296341Sdelphij                   ctx->msg.channel, ctx->msg.function);
26955714Skris
270296341Sdelphij        }
27155714Skris    }
272296341Sdelphij    return (i);
27355714Skris}
27455714Skris
27568651Skrisstatic long rtcp_ctrl(BIO *b, int cmd, long num, void *ptr)
276296341Sdelphij{
277296341Sdelphij    long ret = 1;
27855714Skris
279296341Sdelphij    switch (cmd) {
280296341Sdelphij    case BIO_CTRL_RESET:
281296341Sdelphij    case BIO_CTRL_EOF:
282296341Sdelphij        ret = 1;
283296341Sdelphij        break;
284296341Sdelphij    case BIO_C_SET_FD:
285296341Sdelphij        b->num = num;
286296341Sdelphij        ret = 1;
287296341Sdelphij        break;
288296341Sdelphij    case BIO_CTRL_SET_CLOSE:
289296341Sdelphij    case BIO_CTRL_FLUSH:
290296341Sdelphij    case BIO_CTRL_DUP:
291296341Sdelphij        ret = 1;
292296341Sdelphij        break;
293296341Sdelphij    case BIO_CTRL_GET_CLOSE:
294296341Sdelphij    case BIO_CTRL_INFO:
295296341Sdelphij    case BIO_CTRL_GET:
296296341Sdelphij    case BIO_CTRL_PENDING:
297296341Sdelphij    case BIO_CTRL_WPENDING:
298296341Sdelphij    default:
299296341Sdelphij        ret = 0;
300296341Sdelphij        break;
301296341Sdelphij    }
302296341Sdelphij    return (ret);
303296341Sdelphij}
30455714Skris
30555714Skrisstatic int rtcp_gets(BIO *bp, char *buf, int size)
306296341Sdelphij{
307296341Sdelphij    return (0);
308296341Sdelphij}
30955714Skris
31068651Skrisstatic int rtcp_puts(BIO *bp, const char *str)
31155714Skris{
31255714Skris    int length;
313296341Sdelphij    if (str == NULL)
314296341Sdelphij        return (0);
315296341Sdelphij    length = strlen(str);
316296341Sdelphij    if (length == 0)
317296341Sdelphij        return (0);
318296341Sdelphij    return rtcp_write(bp, str, length);
31955714Skris}
320