Logo Search packages:      
Sourcecode: lebiniou version File versions  Download package

erlang.c

/*
 *  Copyright 1994-2011 Olivier Girondel
 *
 *  This file is part of lebiniou.
 *
 *  lebiniou is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  lebiniou 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with lebiniou. If not, see <http://www.gnu.org/licenses/>.
 */

#include "context.h"

#if HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif


#define PROTOCOL     '5'
#define MAX_PROTOCOL PROTOCOL

char proto = PROTOCOL;

/*
 * Packet format:
 *
 * [ packet size ]        4 bytes
 * [ protocol version ]   4 bytes, should be enough ;)
 * [ protocol specific ]  N bytes
 *
 * See the v?.c files for protocol specific format
 */

u_long id = 1216486988;
u_long options = BE_NONE;

/* erlang port plugin */
#define IN_FD      3
#define OUT_FD     4
#define STOP_CHAR 'S'

FILE *in = NULL, *out = NULL;


extern void v1(const Context_t *);
extern void v2(const Context_t *);
extern void v3(const Context_t *);
extern void v4(const Context_t *);
extern void v5(const Context_t *);


void
create(__attribute__ ((unused)) Context_t *ctx)
{
  int flags;
  char *env;

  in = fdopen(IN_FD, "r");
  if (NULL == in)
    xperror("fdopen");
  if (-1 == (flags = fcntl(IN_FD, F_GETFL, 0)))
    flags = 0;
  if (-1 == fcntl(IN_FD, F_SETFL, flags | O_NONBLOCK))
    xperror("fcntl");

  out = fdopen(OUT_FD, "w");
  if (NULL == out)
    xperror("fdopen");

  env = getenv("BINIOU_ERLANG_PROTO");
  if (NULL != env) {
    char v = env[0];
    if ((v < '1') || (v > MAX_PROTOCOL)) {
      printf("[!] Unknown protocol version '%c', setting to %d\n", v, PROTOCOL);
      proto = PROTOCOL;
    } else {
      printf("[i] erlang: setting protocol to %c\n", v);
      proto = v;
    }
  }
}


void
destroy(__attribute__ ((unused)) Context_t *ctx)
{
  if (fclose(in) != 0)
    xperror("fclose");
  if (fclose(out) != 0)
    xperror("fclose");
}


void
xfwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
{
  size_t res;

  res = fwrite(ptr, size, nmemb, stream);
  if (res != nmemb) {
    fprintf(stderr, "[!] xfwrite: short write (%d vs %d)\n", (int)res, (int)nmemb);
    /* TODO reopen stream ? */
    exit(1);
  }
}


/* did we receive a stop from the erlang side ? */
static int
done()
{
  u_long pkt_size, pkt_size2;
  char cmd = 'O';
  size_t res;

  res = fread((void *)&pkt_size, sizeof(u_long), 1, in);
  if (0 == res)
    return 0;

  pkt_size2 = ntohl(pkt_size);
  if (1 == pkt_size2) {
    res = fread((void *)&cmd, sizeof(char), 1, in);
    
    if (1 == res) { /* got one byte */
      if (cmd == STOP_CHAR)
      return 1;
      else
      xerror("Got wrong command from erlang: '%c' (%d)\n", cmd, cmd);
    } else
      return 0;
  } else
    xerror("Got wrong packet length from erlang: %li\n");

  return 0; /* not reached */
}


void
run(Context_t *ctx)
{
  uint32_t total, total2;

  if (done()) {
    char c = STOP_CHAR;
    
    ctx->running = 0;

    /* ACK stop */
    /* send packet size */
    total = sizeof(char);
    total2 = htonl(total);
    xfwrite((const void *)&total2, sizeof(uint32_t), 1, out);

    /* send STOP_CHAR */
    xfwrite((const void *)&c, sizeof(char), 1, out);
  } else {
    switch (proto) {
    case '1':
      v1(ctx);
      break;

    case '2':
      v2(ctx);
      break;

    case '3':
      v3(ctx);
      break;

    case '4':
      v4(ctx);
      break;

    case '5':
      v5(ctx);
      break;

    default:
      xerror("Unknown protocol version\n");
      break;
    }
  }
}

Generated by  Doxygen 1.6.0   Back to index