--- /dev/null
+/* This file is part of the YAZ toolkit.
+ * Copyright (C) 1995-2010 Index Data.
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Index Data nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file spipe.h
+ * \brief socket-pipe header
+ */
+#ifndef YAZ_SPIPE_H
+#define YAZ_SPIPE_H
+
+#include <stddef.h>
+#include <time.h>
+#include <yaz/yconfig.h>
+#include <yaz/wrbuf.h>
+
+YAZ_BEGIN_CDECL
+
+/** \brief YAZ socket pipe opaque pointer */
+typedef struct yaz_spipe *yaz_spipe_t;
+
+/** \brief create socket pipe
+ \param port_to_use port that we temporarily bind to
+ \param err_msg error message reference (0 if not to be set)
+ \returns 0 on failure; != 0 on success
+ */
+YAZ_EXPORT yaz_spipe_t yaz_spipe_create(int port_to_use, WRBUF *err_msg);
+
+/** \brief destroys socket pipe
+ \param p socket pipe pointer
+ */
+YAZ_EXPORT void yaz_spipe_destroy(yaz_spipe_t p);
+
+/** \brief returns reading socket
+ \param p socket pipe pointer
+ */
+YAZ_EXPORT int yaz_spipe_get_read_fd(yaz_spipe_t p);
+
+/** \brief returns writing socket
+ \param p socket pipe pointer
+ */
+YAZ_EXPORT int yaz_spipe_get_write_fd(yaz_spipe_t p);
+
+YAZ_END_CDECL
+
+#endif
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
--- /dev/null
+/* This file is part of the YAZ toolkit.
+ * Copyright (C) 1995-2010 Index Data
+ * See the file LICENSE for details.
+ */
+
+/**
+ * \file spipe.c
+ * \brief Implements socket-pipes
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <yaz/xmalloc.h>
+#include <yaz/nmem.h>
+#include <yaz/log.h>
+#include <yaz/spipe.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef WIN32
+#include <winsock2.h>
+#define YAZ_INVALID_SOCKET INVALID_SOCKET
+#else
+#define YAZ_INVALID_SOCKET -1
+#include <fcntl.h>
+#endif
+
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <netinet/tcp.h>
+
+struct yaz_spipe {
+ int m_fd[2];
+ int m_socket;
+};
+
+static void yaz_spipe_close(int *fd)
+{
+#ifdef WIN32
+ if (*fd != YAZ_INVALID_SOCKET)
+ closesocket(*fd);
+#else
+ if (*fd != YAZ_INVALID_SOCKET)
+ close(*fd);
+#endif
+ *fd = YAZ_INVALID_SOCKET;
+}
+
+static int nonblock(int s)
+{
+#ifdef WIN32
+ unsigned long tru = 1;
+ if (ioctlsocket(s, FIONBIO, &tru))
+ return -1;
+#else
+ if (fcntl(s, F_SETFL, O_NONBLOCK))
+ return -1;
+#endif
+ return 0;
+}
+
+yaz_spipe_t yaz_spipe_create(int port_to_use, WRBUF *err_msg)
+{
+ yaz_spipe_t p = xmalloc(sizeof(*p));
+
+#ifdef WIN32
+ {
+ WSADATA wsaData;
+ WORD wVersionRequested = MAKEWORD(2, 0);
+ if (WSAStartup( wVersionRequested, &wsaData))
+ {
+ if (err_msg)
+ wrbuf_printf(*err_msg, "WSAStartup failed");
+ xfree(p);
+ return 0;
+ }
+ }
+#endif
+ p->m_fd[0] = p->m_fd[1] = YAZ_INVALID_SOCKET;
+ p->m_socket = YAZ_INVALID_SOCKET;
+
+ if (port_to_use)
+ {
+ struct sockaddr_in add;
+ struct sockaddr *addr = 0;
+ unsigned int tmpadd;
+ struct sockaddr caddr;
+#ifdef WIN32
+ int caddr_len = sizeof(caddr);
+#else
+ socklen_t caddr_len = sizeof(caddr);
+#endif
+ fd_set write_set;
+
+ // create server socket
+ p->m_socket = socket(AF_INET, SOCK_STREAM, 0);
+ if (p->m_socket == YAZ_INVALID_SOCKET)
+ {
+ if (err_msg)
+ wrbuf_printf(*err_msg, "socket call failed");
+ yaz_spipe_destroy(p);
+ return 0;
+ }
+#ifndef WIN32
+ {
+ unsigned long one = 1;
+ if (setsockopt(p->m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)
+ &one, sizeof(one)))
+ {
+ if (err_msg)
+ wrbuf_printf(*err_msg, "setsockopt call failed");
+ yaz_spipe_destroy(p);
+ return 0;
+ }
+ }
+#endif
+ // bind server socket
+ add.sin_family = AF_INET;
+ add.sin_port = htons(port_to_use);
+ add.sin_addr.s_addr = INADDR_ANY;
+ addr = ( struct sockaddr *) &add;
+
+ if (bind(p->m_socket, addr, sizeof(struct sockaddr_in)))
+ {
+ if (err_msg)
+ wrbuf_printf(*err_msg, "could not bind to socket");
+ yaz_spipe_destroy(p);
+ return 0;
+ }
+
+ if (listen(p->m_socket, 3) < 0)
+ {
+ if (err_msg)
+ wrbuf_printf(*err_msg, "could not listen on socket");
+ yaz_spipe_destroy(p);
+ return 0;
+ }
+
+ // client socket
+ tmpadd = (unsigned) inet_addr("127.0.0.1");
+ if (!tmpadd)
+ {
+ if (err_msg)
+ wrbuf_printf(*err_msg, "inet_addr failed");
+ yaz_spipe_destroy(p);
+ return 0;
+ }
+
+ memcpy(&add.sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
+ p->m_fd[1] = socket(AF_INET, SOCK_STREAM, 0);
+ if (p->m_fd[1] == YAZ_INVALID_SOCKET)
+ {
+ if (err_msg)
+ wrbuf_printf(*err_msg, "socket call failed (2)");
+ yaz_spipe_destroy(p);
+ return 0;
+ }
+ nonblock(p->m_fd[1]);
+
+ if (connect(p->m_fd[1], addr, sizeof(*addr)))
+ {
+ if (
+#ifdef WIN32
+ WSAGetLastError() != WSAEWOULDBLOCK
+#else
+ errno != EINPROGRESS
+#endif
+ )
+ {
+ if (err_msg)
+ wrbuf_printf(*err_msg, "connect call failed");
+ yaz_spipe_destroy(p);
+ return 0;
+ }
+ }
+
+ /* server accept */
+ p->m_fd[0] = accept(p->m_socket, &caddr, &caddr_len);
+ if (p->m_fd[0] == YAZ_INVALID_SOCKET)
+ {
+ if (err_msg)
+ wrbuf_printf(*err_msg, "accept failed");
+ yaz_spipe_destroy(p);
+ return 0;
+ }
+
+ /* complete connect */
+ FD_ZERO(&write_set);
+ FD_SET(p->m_fd[1], &write_set);
+ if (select(p->m_fd[1]+1, 0, &write_set, 0, 0) != 1)
+ {
+ if (err_msg)
+ wrbuf_printf(*err_msg, "could not complete connect");
+ yaz_spipe_destroy(p);
+ return 0;
+ }
+ yaz_spipe_close(&p->m_socket);
+ }
+ else
+ {
+#ifdef WIN32
+ yaz_spipe_destroy(p);
+ return 0;
+#else
+ if (pipe(p->m_fd))
+ {
+ if (err_msg)
+ wrbuf_printf(*err_msg, "pipe call failed");
+ yaz_spipe_destroy(p);
+ return 0;
+ }
+ assert(p->m_fd[0] != YAZ_INVALID_SOCKET);
+ assert(p->m_fd[1] != YAZ_INVALID_SOCKET);
+#endif
+ }
+
+ return p;
+}
+
+void yaz_spipe_destroy(yaz_spipe_t p)
+{
+ yaz_spipe_close(&p->m_fd[0]);
+ yaz_spipe_close(&p->m_fd[1]);
+ yaz_spipe_close(&p->m_socket);
+ xfree(p);
+#ifdef WIN32
+ WSACleanup();
+#endif
+}
+
+int yaz_spipe_get_read_fd(yaz_spipe_t p)
+{
+ return p->m_fd[0];
+}
+
+int yaz_spipe_get_write_fd(yaz_spipe_t p)
+{
+ return p->m_fd[1];
+}
+
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+