DirectResult voodoo_link_init_connect( VoodooLink *link, const char *hostname, int port, bool raw ) { DirectResult ret; int err; struct addrinfo hints; struct addrinfo *addr; char portstr[10]; Link *l; memset( &hints, 0, sizeof(hints) ); hints.ai_flags = AI_CANONNAME; hints.ai_socktype = SOCK_STREAM; hints.ai_family = PF_UNSPEC; D_INFO( "Voodoo/Link: Looking up host '%s'...\n", hostname ); snprintf( portstr, sizeof(portstr), "%d", port ); err = getaddrinfo( hostname, portstr, &hints, &addr ); if (err) { switch (err) { case EAI_FAMILY: D_ERROR( "Direct/Log: Unsupported address family!\n" ); return DR_UNSUPPORTED; case EAI_SOCKTYPE: D_ERROR( "Direct/Log: Unsupported socket type!\n" ); return DR_UNSUPPORTED; case EAI_NONAME: D_ERROR( "Direct/Log: Host not found!\n" ); return DR_FAILURE; case EAI_SERVICE: D_ERROR( "Direct/Log: Service is unreachable!\n" ); return DR_FAILURE; #ifdef EAI_ADDRFAMILY case EAI_ADDRFAMILY: #endif case EAI_NODATA: D_ERROR( "Direct/Log: Host found, but has no address!\n" ); return DR_FAILURE; case EAI_MEMORY: return D_OOM(); case EAI_FAIL: D_ERROR( "Direct/Log: A non-recoverable name server error occurred!\n" ); return DR_FAILURE; case EAI_AGAIN: D_ERROR( "Direct/Log: Temporary error, try again!\n" ); return DR_TEMPUNAVAIL; default: D_ERROR( "Direct/Log: Unknown error occured!?\n" ); return DR_FAILURE; } } l = D_CALLOC( 1, sizeof(Link) ); if (!l) return D_OOM(); /* Create the client socket. */ l->fd[0] = socket( addr->ai_family, SOCK_STREAM, 0 ); if (l->fd[0] < 0) { ret = errno2result( errno ); D_PERROR( "Voodoo/Link: Socket creation failed!\n" ); freeaddrinfo( addr ); D_FREE( l ); return ret; } l->fd[1] = l->fd[0]; #if !VOODOO_BUILD_NO_SETSOCKOPT if (setsockopt( l->fd[0], SOL_IP, IP_TOS, &tos, sizeof(tos) ) < 0) D_PERROR( "Voodoo/Manager: Could not set IP_TOS!\n" ); if (setsockopt( l->fd[0], SOL_TCP, TCP_NODELAY, &one, sizeof(one) ) < 0) D_PERROR( "Voodoo/Manager: Could not set TCP_NODELAY!\n" ); #endif D_INFO( "Voodoo/Link: Connecting to '%s:%d'...\n", addr->ai_canonname, port ); /* Connect to the server. */ err = connect( l->fd[0], addr->ai_addr, addr->ai_addrlen ); freeaddrinfo( addr ); if (err) { ret = errno2result( errno ); D_PERROR( "Voodoo/Link: Socket connect failed!\n" ); close( l->fd[0] ); D_FREE( l ); return ret; } D_INFO( "Voodoo/Link: Connected.\n" ); DUMP_SOCKET_OPTION( l->fd[0], SO_SNDLOWAT ); DUMP_SOCKET_OPTION( l->fd[0], SO_RCVLOWAT ); DUMP_SOCKET_OPTION( l->fd[0], SO_SNDBUF ); DUMP_SOCKET_OPTION( l->fd[0], SO_RCVBUF ); if (!raw) { link->code = 0x80008676; if (write( l->fd[1], &link->code, sizeof(link->code) ) != 4) { D_ERROR( "Voodoo/Link: Coult not write initial four bytes!\n" ); close( l->fd[0] ); D_FREE( l ); return DR_IO; } } D_INFO( "Voodoo/Link: Sent link code (%s).\n", raw ? "raw" : "packet" ); if (pipe( l->wakeup_fds )) return errno2result( errno ); link->priv = l; link->Close = Close; link->Read = Read; link->Write = Write; link->SendReceive = SendReceive; link->WakeUp = WakeUp; link->WaitForData = WaitForData; return DR_OK; }
DirectResult voodoo_link_init_local( VoodooLink *link, const char *path, bool raw ) { DirectResult ret; int err; struct sockaddr_un addr; Link *l; D_ASSERT( link != NULL ); D_ASSERT( path != NULL ); l = D_CALLOC( 1, sizeof(Link) ); if (!l) return D_OOM(); /* Create the client socket. */ l->fd[0] = socket( AF_LOCAL, SOCK_STREAM, 0 ); if (l->fd[0] < 0) { ret = errno2result( errno ); D_PERROR( "Voodoo/Link: Socket creation failed!\n" ); D_FREE( l ); return ret; } l->fd[1] = l->fd[0]; #if !VOODOO_BUILD_NO_SETSOCKOPT if (setsockopt( l->fd[0], SOL_IP, IP_TOS, &tos, sizeof(tos) ) < 0) D_PERROR( "Voodoo/Manager: Could not set IP_TOS!\n" ); if (setsockopt( l->fd[0], SOL_TCP, TCP_NODELAY, &one, sizeof(one) ) < 0) D_PERROR( "Voodoo/Manager: Could not set TCP_NODELAY!\n" ); #endif D_INFO( "Voodoo/Link: Connecting to '%s'...\n", path ); memset( &addr, 0, sizeof(addr) ); /* Bind the socket to the local port. */ addr.sun_family = AF_UNIX; snprintf( addr.sun_path + 1, UNIX_PATH_MAX - 1, "%s", path ); /* Connect to the server. */ err = connect( l->fd[0], (struct sockaddr*) &addr, strlen(addr.sun_path+1)+1 + sizeof(addr.sun_family) ); if (err) { ret = errno2result( errno ); D_PERROR( "Voodoo/Link: Socket connect failed!\n" ); close( l->fd[0] ); D_FREE( l ); return ret; } D_INFO( "Voodoo/Link: Connected.\n" ); DUMP_SOCKET_OPTION( l->fd[0], SO_SNDLOWAT ); DUMP_SOCKET_OPTION( l->fd[0], SO_RCVLOWAT ); DUMP_SOCKET_OPTION( l->fd[0], SO_SNDBUF ); DUMP_SOCKET_OPTION( l->fd[0], SO_RCVBUF ); if (!raw) { link->code = 0x80008676; if (write( l->fd[1], &link->code, sizeof(link->code) ) != 4) { D_ERROR( "Voodoo/Link: Coult not write initial four bytes!\n" ); close( l->fd[0] ); D_FREE( l ); return DR_IO; } } D_INFO( "Voodoo/Link: Sent link code (%s).\n", raw ? "raw" : "packet" ); if (pipe( l->wakeup_fds )) return errno2result( errno ); link->priv = l; link->Close = Close; link->Read = Read; link->Write = Write; link->SendReceive = SendReceive; link->WakeUp = WakeUp; link->WaitForData = WaitForData; return DR_OK; }
DirectResult voodoo_manager_create( int fd, VoodooClient *client, VoodooServer *server, VoodooManager **ret_manager ) { DirectResult ret; VoodooManager *manager; int val; unsigned int len; static const int tos = IPTOS_LOWDELAY; D_ASSERT( fd >= 0 ); D_ASSERT( (client != NULL) ^ (server != NULL) ); D_ASSERT( ret_manager != NULL ); /* Allocate manager structure. */ manager = D_CALLOC( 1, sizeof(VoodooManager) ); if (!manager) { D_WARN( "out of memory" ); return DR_NOLOCALMEMORY; } D_DEBUG( "Voodoo/Manager: Creating manager at %p.\n", manager ); if (setsockopt( fd, SOL_IP, IP_TOS, &tos, sizeof(tos) ) < 0) D_PERROR( "Voodoo/Manager: Could not set IP_TOS!\n" ); if (setsockopt( fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one) ) < 0) D_PERROR( "Voodoo/Manager: Could not set TCP_NODELAY!\n" ); DUMP_SOCKET_OPTION( SO_SNDLOWAT ); DUMP_SOCKET_OPTION( SO_RCVLOWAT ); DUMP_SOCKET_OPTION( SO_SNDBUF ); DUMP_SOCKET_OPTION( SO_RCVBUF ); /* Create the hash table for dispatcher instances. */ ret = direct_hash_create( 251, &manager->instances.local ); if (ret) { D_FREE( manager ); return ret; } /* Create the hash table for requestor instances. */ ret = direct_hash_create( 251, &manager->instances.remote ); if (ret) { direct_hash_destroy( manager->instances.local ); D_FREE( manager ); return ret; } /* Store file descriptor. */ manager->fd = fd; /* Store client or server. */ manager->client = client; manager->server = server; /* Initialize all locks. */ direct_util_recursive_pthread_mutex_init( &manager->instances.lock ); direct_util_recursive_pthread_mutex_init( &manager->response.lock ); direct_util_recursive_pthread_mutex_init( &manager->input.lock ); direct_util_recursive_pthread_mutex_init( &manager->output.lock ); /* Initialize all wait conditions. */ pthread_cond_init( &manager->response.wait, NULL ); pthread_cond_init( &manager->input.wait, NULL ); pthread_cond_init( &manager->output.wait, NULL ); /* Set default buffer limit. */ manager->input.max = IN_BUF_MAX; D_MAGIC_SET( manager, VoodooManager ); /* Create all threads. */ manager->dispatcher = direct_thread_create( DTT_MESSAGING, manager_dispatch_loop, manager, "Voodoo Dispatch" ); manager->input.thread = direct_thread_create( DTT_INPUT, manager_input_loop, manager, "Voodoo Input" ); manager->output.thread = direct_thread_create( DTT_OUTPUT, manager_output_loop, manager, "Voodoo Output" ); /* Return the new manager. */ *ret_manager = manager; return DR_OK; }