From: Adam Dickmeiss Date: Thu, 20 May 2010 11:32:48 +0000 (+0200) Subject: Add socket pipe utility X-Git-Tag: v4.0.9~3^2~1 X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=commitdiff_plain;h=7dc39ebcca4138d27f9a0e5082b2829a7c96375a;hp=f3700fe68a59e969d9ef1f98e1748e10f4a80471 Add socket pipe utility The socket pipe has same purpose as Unix pipe . Unfortunately Windows pipes do not work on select/poll. --- diff --git a/include/yaz/Makefile.am b/include/yaz/Makefile.am index 28dd159..015c5a7 100644 --- a/include/yaz/Makefile.am +++ b/include/yaz/Makefile.am @@ -20,7 +20,8 @@ pkginclude_HEADERS= backend.h ccl.h ccl_xml.h cql.h rpn2cql.h comstack.h \ z-univ.h z-oclcui.h zes-expi.h zes-exps.h zes-order.h zes-pquery.h \ zes-psched.h zes-admin.h zes-pset.h zes-update.h zes-update0.h \ zoom.h z-charneg.h charneg.h soap.h srw.h zgdu.h matchstr.h json.h \ - file_glob.h dirent.h thread_id.h gettimeofday.h shptr.h thread_create.h + file_glob.h dirent.h thread_id.h gettimeofday.h shptr.h thread_create.h \ + spipe.h EXTRA_DIST = yaz-version.h.in diff --git a/include/yaz/spipe.h b/include/yaz/spipe.h new file mode 100644 index 0000000..1b48650 --- /dev/null +++ b/include/yaz/spipe.h @@ -0,0 +1,78 @@ +/* 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 +#include +#include +#include + +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 + */ + diff --git a/src/Makefile.am b/src/Makefile.am index cfa34cb..d8dd1e9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -103,7 +103,7 @@ libyaz_la_SOURCES=version.c options.c log.c \ iconv_encode_marc8.c iconv_encode_iso_8859_1.c iconv_encode_wchar.c \ iconv_decode_marc8.c iconv_decode_iso5426.c iconv_decode_danmarc.c sc.c \ json.c xml_include.c file_glob.c dirent.c mutex-p.h mutex.c condvar.c \ - thread_id.c gettimeofday.c thread_create.c + thread_id.c gettimeofday.c thread_create.c spipe.c libyaz_la_LDFLAGS=-version-info $(YAZ_VERSION_INFO) diff --git a/src/spipe.c b/src/spipe.c new file mode 100644 index 0000000..f42c8f1 --- /dev/null +++ b/src/spipe.c @@ -0,0 +1,275 @@ +/* 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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#endif + +#ifdef WIN32 +#include +#define YAZ_INVALID_SOCKET INVALID_SOCKET +#else +#define YAZ_INVALID_SOCKET -1 +#include +#endif + +#if HAVE_NETINET_IN_H +#include +#endif +#if HAVE_NETDB_H +#include +#endif +#if HAVE_ARPA_INET_H +#include +#endif +#if HAVE_NETINET_TCP_H +#include +#endif +#if HAVE_SYS_SOCKET_H +#include +#endif + +#include +#include +#include +#include + +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 + */ + diff --git a/win/makefile b/win/makefile index 77d27e2..7933622 100644 --- a/win/makefile +++ b/win/makefile @@ -505,6 +505,7 @@ MISC_OBJS= \ $(OBJDIR)\iconv_decode_danmarc.obj \ $(OBJDIR)\mutex.obj \ $(OBJDIR)\thread_create.obj \ + $(OBJDIR)\spipe.obj \ $(OBJDIR)\gettimeofday.obj \ $(OBJDIR)\json.obj \ $(OBJDIR)\sc.obj \