/** * @file server-client.c * * * @brief サーバ・クライアント接続 * * * * @brief Server client connection * * * @author Akinobu LEE * @date Wed Feb 16 07:18:13 2005 * * $Revision: 1.5 $ * */ /* * Copyright (c) 1991-2012 Kawahara Lab., Kyoto University * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology * Copyright (c) 2005-2012 Julius project team, Nagoya Institute of Technology * All rights reserved */ #include #include #ifdef WINSOCK boolean winsock_initialized = FALSE; ///< TRUE if once initialized #endif /** * Prepare as a server creating a socket for client connection. * * @param port_num [in] network port to listen. * * @return socket descriptor, or -1 if failed to create socket, * -2 if failed to bind, or -3 if failed to listen. */ int ready_as_server(int port_num) { struct sockaddr_in sin; int sd; int optval; int optlen; #ifdef WINSOCK /* init winsock */ if (!winsock_initialized) { WSADATA data; WSAStartup(MAKEWORD(2,0), &data); winsock_initialized = TRUE; } #endif /* create socket */ #ifdef WINSOCK if((sd = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) == INVALID_SOCKET){ jlog("Error: server-client: socket() error\n"); jlog("Error: server-client: error code = %d\n", WSAGetLastError()); switch(WSAGetLastError()) { case WSANOTINITIALISED: jlog("Error: server-client: reason: A successful WSAStartup must occur before using this function.\n"); break; case WSAENETDOWN: jlog("Error: server-client: reason: The network subsystem or the associated service provider has failed.\n"); break; case WSAEAFNOSUPPORT: jlog("Error: server-client: reason: The specified address family is not supported. \n"); break; case WSAEINPROGRESS: jlog("Error: server-client: reason: A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function. \n"); break; case WSAEMFILE: jlog("Error: server-client: reason: No more socket descriptors are available. \n"); break; case WSAENOBUFS: jlog("Error: server-client: reason: No buffer space is available. The socket cannot be created. \n"); break; case WSAEPROTONOSUPPORT: jlog("Error: server-client: reason: The specified protocol is not supported. \n"); break; case WSAEPROTOTYPE: jlog("Error: server-client: reason: The specified protocol is the wrong type for this socket. \n"); break; case WSAESOCKTNOSUPPORT: jlog("Error: server-client: reason: The specified socket type is not supported in this address family. \n"); break; } return -1; } #else /* ~WINSOCK */ if((sd = socket(PF_INET, SOCK_STREAM, 0)) < 0){ jlog("Error: server-client: socket() error\n"); return -1; } #endif /* ~WINSOCK */ /* set socket to allow reuse of local address at bind() */ /* this option prevent from "error: Address already in use" */ optval = 1; optlen = sizeof(int); if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, optlen) != 0) { jlog("Error: server-client: socketopt() error\n"); return -2; } /* assign name(address) to socket */ memset((char *)&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons((unsigned short)port_num); if(bind(sd, (struct sockaddr *)&sin, sizeof(sin)) < 0){ jlog("Error: server-client: bind() error\n"); return -2; } /* begin to listen */ if (listen(sd, 5) < 0) { jlog("Error: server-client: listen() error\n"); return -3; } jlog("Stat: server-client: socket ready as server\n"); return(sd); } /** * @brief Wait for a request from client. * * This function blocks until a connection request comes. * * @param sd [in] listening server socket descpritor * * @return the connected socket descriptor. */ int accept_from(int sd) { static struct sockaddr_in from; #ifdef HAVE_SOCKLEN_T static socklen_t nbyte; #else static int nbyte; #endif /* HAVE_SOCKLEN_T */ int asd; nbyte = sizeof(struct sockaddr_in); asd = accept(sd, (struct sockaddr *)&from, &nbyte); if (asd < 0) { /* error */ jlog("Error: server-client: accept() error\n"); jlog("Error: server-client: failed to accept connection\n"); #ifdef WINSOCK switch(WSAGetLastError()) { case WSANOTINITIALISED: jlog("Error: server-client: reason: A successful WSAStartup must occur before using this FUNCTION. \n"); break; case WSAENETDOWN: jlog("Error: server-client: reason: The network subsystem has failed. \n"); break; case WSAEFAULT: jlog("Error: server-client: reason: The addrlen parameter is too small or addr is not a valid part of the user address space. \n"); break; case WSAEINTR: jlog("Error: server-client: reason: A blocking Windows Sockets 1.1 call was canceled through WSACancelBlockingCall. \n"); break; case WSAEINPROGRESS: jlog("Error: server-client: reason: A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function. \n"); break; case WSAEINVAL: jlog("Error: server-client: reason: The listen function was not invoked prior to accept. \n"); break; case WSAEMFILE: jlog("Error: server-client: reason: The queue is nonempty upon entry to accept and there are no descriptors available. \n"); break; case WSAENOBUFS: jlog("Error: server-client: reason: No buffer space is available. \n"); break; case WSAENOTSOCK: jlog("Error: server-client: reason: The descriptor is not a socket. \n"); break; case WSAEOPNOTSUPP: jlog("Error: server-client: reason: The referenced socket is not a type that supports connection-oriented service. \n"); break; case WSAEWOULDBLOCK: jlog("Error: server-client: reason: The socket is marked as nonblocking and no connections are present to be accepted. \n"); break; } #endif return -1; } jlog("Stat: server-client: connect from %s\n", inet_ntoa(from.sin_addr)); return asd; } /** * Make a connection to a server. * * @param hostname [in] server host (host name or numeric IP address) * @param port_num [in] port number * * @return new socket descriptor, -1 if fails to prepare socket, -2 if fails to connect, -3 if host name is wrong. */ int make_connection(char *hostname, int port_num) { static struct hostent *hp; static struct sockaddr_in sin; int sd; int trynum; #ifdef WINSOCK /* init winsock */ if (!winsock_initialized) { WSADATA data; WSAStartup(0x1010, &data); winsock_initialized = TRUE; } #endif /* host existence check */ if ((hp = gethostbyname(hostname)) == NULL) { jlog("Error: server-client: target host not found: %s\n", hostname); return -3; } /* create socket */ #ifdef WINSOCK if((sd = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET){ jlog("Error: server-client: failed to create socket\n") ; jlog("Error: server-client: Error code: %d\n", WSAGetLastError()); switch(WSAGetLastError()) { case WSANOTINITIALISED: jlog("Error: server-client: reason: A successful WSAStartup must occur before using this function.\n"); break; case WSAENETDOWN: jlog("Error: server-client: reason: The network subsystem or the associated service provider has failed.\n"); break; case WSAEAFNOSUPPORT: jlog("Error: server-client: reason: The specified address family is not supported. \n"); break; case WSAEINPROGRESS: jlog("Error: server-client: reason: A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function. \n"); break; case WSAEMFILE: jlog("Error: server-client: reason: No more socket descriptors are available. \n"); break; case WSAENOBUFS: jlog("Error: server-client: reason: No buffer space is available. The socket cannot be created. \n"); break; case WSAEPROTONOSUPPORT: jlog("Error: server-client: reason: The specified protocol is not supported. \n"); break; case WSAEPROTOTYPE: jlog("Error: server-client: reason: The specified protocol is the wrong type for this socket. \n"); break; case WSAESOCKTNOSUPPORT: jlog("Error: server-client: reason: The specified socket type is not supported in this address family. \n"); break; } return -1; } #else /* ~WINSOCK */ if((sd = socket(PF_INET, SOCK_STREAM, 0)) < 0){ jlog("Error: server-client: failed to create socket\n") ; return -1; } #endif /* ~WINSOCK */ /* try to connect */ for (trynum = 0; trynum < CONNECTION_RETRY_TIMES; trynum++) { memset((char *)&sin, 0, sizeof(sin)); memcpy(&sin.sin_addr, hp->h_addr, hp->h_length); sin.sin_family = hp->h_addrtype; sin.sin_port = htons((unsigned short)port_num); if (connect(sd, (struct sockaddr *)&sin, sizeof(sin)) >= 0) { /* success */ break; } else { /* failure */ jlog("Stat: server-client: conection failed\n") ; /* retry */ jlog("Stat: server-client: retry after %d second...\n", CONNECTION_RETRY_INTERVAL); sleep(CONNECTION_RETRY_INTERVAL); } } if (trynum == CONNECTION_RETRY_TIMES) { /* finally failed */ jlog("Error: server-client: failed to connect to %s:%d\n", hostname, port_num); return -2; } return sd; } #ifndef WINSOCK /** * Make a connection to a server using unix domain socket. * * @param address [in] unix domain socket address (path) * * @return new socket descriptor, -1 if fails to prepare socket, * -2 if fails to connect. */ int make_connection_unix(char *address) { struct sockaddr_un ps; int len; int sd; ps.sun_family = PF_UNIX; strcpy(ps.sun_path, address); len = sizeof(ps.sun_family) + strlen(ps.sun_path); if((sd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){ jlog("Error: server-client: failed to create socket\n"); return -1; } while(connect(sd, (struct sockaddr *)&ps, len) < 0){ jlog("Error: server-client: failed to conect to %s\n", address); /* retry */ jlog("Error: server-client: retry after %d sec...\n",CONNECTION_RETRY_INTERVAL); sleep(CONNECTION_RETRY_INTERVAL); } jlog("Stat: server-client: connected to unix socket %s\n", address); return sd; } #endif /* ~WINSOCK */ /** * Close socket. * * @param sd [in] socket descriptor to close * * @return 0 on success, -1 on failure. */ int close_socket(int sd) { int ret; #ifdef WINSOCK ret = closesocket(sd); #else ret = close(sd); #endif return(ret); } /** * Clean up socket data at program exit. * */ void cleanup_socket() { #ifdef WINSOCK if (winsock_initialized) { WSACleanup(); } #endif }