/*
* 1999-2008
* Ericsson AB, All Rights Reserved
*
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Initial Developer of the Original Code is Ericsson AB.
*
*/
/*
* Purpose: Std filedescriptors, break handler
*
*/
#include
#include
#ifdef __WIN32__
#include "esock_winsock.h"
#include
#include
#include
#else
#include
#include
#endif
#include "esock.h"
#include "debuglog.h"
#include "esock_utils.h"
#include "esock_osio.h"
#ifdef __WIN32__
#define write _write
#define read _read
#define LOCALHOSTADDR "127.0.0.1"
#define LOCBUFSIZE 1024
#endif
#define PACKET_SIZE 4
#define EBUFSIZE 256
FD local_read_fd = 0;
static int inc_rbuf(int size);
static void free_rbuf(void);
static int read_fill(unsigned char *buf, int len);
#ifdef __WIN32__
static int create_local_thread(void);
static DWORD WINAPI local_thread(LPVOID lpvParam);
static BOOL WINAPI signal_handler(DWORD ctrl);
#endif
static unsigned char *rbuf = NULL;
static int rbuf_malloced = 0;
#ifdef __WIN32__
static unsigned long one = 1, zero = 0;
static int local_portno;
static char *local_buf;
#endif
int set_break_handler(void)
{
#ifndef __WIN32__
struct sigaction act;
/* Ignore SIGPIPE signal */
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, NULL);
return 0;
#else
SetConsoleCtrlHandler(signal_handler, TRUE);
return 0;
#endif
}
#ifdef __WIN32__
int set_binary_mode(void)
{
_setmode(0, _O_BINARY);
_setmode(1, _O_BINARY);
return 0;
}
int esock_osio_init(void)
{
return create_local_thread();
}
void esock_osio_finish(void)
{
sock_close(local_read_fd);
}
#endif
int read_ctrl(unsigned char **ebufp)
{
int tbh, cc;
unsigned char *mbuf;
if (inc_rbuf(EBUFSIZE) < 0) {
fprintf(stderr, "read_ctrl: cannot alloc rbuf\n");
return -1;
}
cc = read_fill(rbuf, PACKET_SIZE);
if (cc < 0) {
free_rbuf();
return -1;
}
if (cc == 0) {
free_rbuf();
return -1; /* XXX 0 ?? */
}
tbh = GET_INT32(rbuf);
if (tbh > rbuf_malloced - 4) {
if (inc_rbuf(tbh + 4) < 0)
return -1;
}
mbuf = rbuf + PACKET_SIZE;
cc = read_fill(mbuf, tbh);
DEBUGF(("-----------------------------------\n"));
DEBUGF(("read_ctrl: cc = %d\n", cc));
if(cc > 0) {
DEBUGMSGF(("message (hex) : [%3.*a]\n", cc, mbuf));
DEBUGMSGF(("message (char): [%3.*b]\n", cc, mbuf));
}
*ebufp = mbuf;
return cc;
}
int write_ctrl(unsigned char *buf, int len)
{
unsigned char lb[4];
PUT_INT32(len, lb);
DEBUGF(("write_ctrl: len = %d\n", len));
DEBUGMSGF(("message (hex) : [%3.*a] [%3.*a]\n", PACKET_SIZE, lb,
len, buf));
DEBUGMSGF(("message (char): [%3.*b] [%3.*b]\n", PACKET_SIZE, lb,
len, buf));
if (write(1, lb, PACKET_SIZE) != PACKET_SIZE) { /* XXX */
fprintf(stderr, "write_ctrl: Bad write \n");
return -1;
}
if (write(1, buf, len) != len) { /* XXX */
fprintf(stderr, "write_ctrl: Bad write \n");
return -1;
}
return len;
}
/*
* Local functions
*
*/
static int inc_rbuf(int size)
{
unsigned char *nbuf;
if (rbuf_malloced >= size)
return 0;
if (rbuf != NULL)
nbuf = esock_realloc(rbuf, size);
else
nbuf = esock_malloc(size);
if(nbuf != NULL) {
rbuf = nbuf;
rbuf_malloced = size;
return 0;
}
return -1;
}
static void free_rbuf(void)
{
if (rbuf != NULL) {
esock_free(rbuf);
rbuf = NULL;
rbuf_malloced = 0;
}
}
/* Fill buffer, return buffer length, 0 for EOF, < 0 for error. */
static int read_fill(unsigned char *buf, int len)
{
int i, got = 0;
do {
if ((i = sock_read(local_read_fd, buf+got, len-got)) <= 0)
return i;
got += i;
} while (got < len);
return len;
}
#ifdef __WIN32__
/*
* This routine creates a local thread, which reads from standard input
* and writes to a socket.
*/
static int create_local_thread(void)
{
struct sockaddr_in iserv_addr;
SOCKET tmpsock;
int length;
unsigned threadaddr;
local_buf = esock_malloc(LOCBUFSIZE);
if ((tmpsock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
fprintf(stderr, "create_local_thread could not create socket.\n");
return -1;
}
memset(&iserv_addr, 0, sizeof(iserv_addr));
iserv_addr.sin_family = AF_INET;
iserv_addr.sin_addr.s_addr = inet_addr(LOCALHOSTADDR);
iserv_addr.sin_port = htons(0); /* Have any port */
if (bind(tmpsock, (struct sockaddr *) &iserv_addr,
sizeof(iserv_addr)) < 0) {
fprintf(stderr, "create_local_thread could not bind.\n");
closesocket(tmpsock);
return -1;
}
listen(tmpsock, 1);
length = sizeof(iserv_addr);
if (getsockname(tmpsock, (struct sockaddr *) &iserv_addr, &length) < 0) {
fprintf(stderr, "create_local_thread could not getsockname.\n");
closesocket(tmpsock);
return -1;
}
local_portno = ntohs(iserv_addr.sin_port);
if (_beginthreadex(NULL, 0, local_thread, NULL, 0, &threadaddr) == 0) {
fprintf(stderr, "create_local_thread could not _beginthreadex().\n");
closesocket(tmpsock);
return -1;
}
local_read_fd = accept(tmpsock, (struct sockaddr *) NULL, (int *) NULL);
if (local_read_fd == INVALID_FD) {
fprintf(stderr, "create_local_thread could not accept.\n");
closesocket(tmpsock);
return -1;
}
closesocket(tmpsock);
return 0;
}
static DWORD WINAPI local_thread(LPVOID lpvParam)
{
SOCKET sock;
struct hostent *host;
char hostname[64];
struct sockaddr_in iserv_addr;
unsigned long addr;
int len;
HANDLE thread;
sock = socket(AF_INET, SOCK_STREAM, 0);
memset(&iserv_addr, 0, sizeof(struct sockaddr_in));
iserv_addr.sin_family = AF_INET;
iserv_addr.sin_addr.s_addr = inet_addr(LOCALHOSTADDR);
iserv_addr.sin_port = htons(local_portno);
if(connect(sock, (struct sockaddr*)&iserv_addr, sizeof iserv_addr) ==
SOCKET_ERROR) {
fprintf(stderr, "local_thread thread could not connect\n");
closesocket(sock);
return 0;
}
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
/* read from 0 and write to sock */
while (1) {
if ((len = read(0, local_buf, LOCBUFSIZE)) <= 0) {
closesocket(sock);
close(0);
return 0;
}
if (send(sock, local_buf, len, 0) != len ) {
closesocket(sock);
close(0);
return 0;
}
}
return 0;
}
/* Signal handler */
static BOOL WINAPI signal_handler(DWORD ctrl)
{
switch (ctrl) {
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
break;
case CTRL_LOGOFF_EVENT:
if (!getenv("ERLSRV_SERVICE_NAME"))
return FALSE;
break;
default:
exit(1);
}
return TRUE;
}
#endif