/* This file is part of the YAZ toolkit. * Copyright (C) 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_SELECT_H #include #endif #if HAVE_SYS_SOCKET_H #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 #ifndef YAZ_SOCKLEN_T #define YAZ_SOCKLEN_T int #endif 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; YAZ_SOCKLEN_T caddr_len = sizeof(caddr); 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 */