### Eclipse Workspace Patch 1.0 #P org.eclipse.tm.tcf.agent Index: framework/channel_tcp.c =================================================================== --- framework/channel_tcp.c (revision 1284) +++ framework/channel_tcp.c (working copy) @@ -24,6 +24,7 @@ #include #include #include +#include #if ENABLE_SSL # include # include @@ -643,27 +644,29 @@ ibuf_trigger_read(&c->ibuf); } -static ChannelTCP * create_channel(int sock, int en_ssl, int server) { +static ChannelTCP * create_channel(int sock, int en_ssl, int server, int unix_domain) { const int i = 1; ChannelTCP * c = NULL; SSL * ssl = NULL; assert(sock >= 0); - if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i)) < 0) { - int error = errno; - trace(LOG_ALWAYS, "Can't set TCP_NODELAY option on a socket: %s", errno_to_str(error)); - closesocket(sock); - errno = error; - return NULL; + if (!unix_domain) { + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i)) < 0) { + int error = errno; + trace(LOG_ALWAYS, "Can't set TCP_NODELAY option on a socket: %s", errno_to_str(error)); + closesocket(sock); + errno = error; + return NULL; + } + if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, sizeof(i)) < 0) { + int error = errno; + trace(LOG_ALWAYS, "Can't set SO_KEEPALIVE option on a socket: %s", errno_to_str(error)); + closesocket(sock); + errno = error; + return NULL; + } } - if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, sizeof(i)) < 0) { - int error = errno; - trace(LOG_ALWAYS, "Can't set SO_KEEPALIVE option on a socket: %s", errno_to_str(error)); - closesocket(sock); - errno = error; - return NULL; - } - + if (en_ssl) { #if ENABLE_SSL long opts = 0; @@ -850,7 +853,8 @@ sock = req->u.acc.rval; peer_addr = si->addr; async_req_post(req); - c = create_channel(sock, strcmp(peer_server_getprop(si->ps, "TransportName", ""), "SSL") == 0, 1); + c = create_channel(sock, strcmp(peer_server_getprop(si->ps, "TransportName", ""), "SSL") == 0, 1, + peer_addr.sa_family == AF_UNIX); if (c == NULL) return; set_peer_addr(c, &peer_addr); si->serv.new_conn(&si->serv, &c->chan); @@ -875,6 +879,106 @@ setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&rcv_buf, sizeof(rcv_buf)); } +static ChannelServer * channel_server_create(PeerServer * ps, int sock) { + ServerTCP * si; + + si = (ServerTCP *)loc_alloc_zero(sizeof *si); + si->serv.close = server_close; + si->sock = sock; + si->ps = ps; + if (server_list.next == NULL) list_init(&server_list); + if (list_is_empty(&server_list)) { + post_event_with_delay(refresh_all_peer_server, NULL, PEER_DATA_REFRESH_PERIOD * 1000000); + } + list_add_last(&si->servlink, &server_list); + refresh_peer_server(sock, ps); + + si->accreq.done = tcp_server_accept_done; + si->accreq.client_data = si; + si->accreq.type = AsyncReqAccept; + si->accreq.u.acc.sock = sock; + si->accreq.u.acc.addr = &si->addr; + si->accreq.u.acc.addrlen = sizeof(si->addr); + async_req_post(&si->accreq); + return &si->serv; +} + +ChannelServer * channel_unix_server(PeerServer * ps) { + int sock; + int error; + const char* reason = 0; + struct sockaddr_un localhost; + + const char * host = peer_server_getprop(ps, "Host", NULL); + if (host == NULL) { + errno = ERR_UNKNOWN_PEER; + return NULL; + } + + assert(is_dispatch_thread()); + + memset(&localhost, 0, sizeof localhost); + + trace(LOG_ALWAYS, "Configuring Unix domain socket on %s for local connection", host); + + error = 0; + + if (strlen(host) >= sizeof(localhost.sun_path)) + { + errno = E2BIG; + trace(LOG_ALWAYS, "Socket file path is too long (%d > %d)", strlen(host), sizeof(localhost.sun_path) - 1); + return NULL; + } + + sock = socket(PF_UNIX, SOCK_STREAM, 0); + if (sock < 0) { + error = errno; + trace(LOG_ALWAYS, "Socket create error on %s: %s", reason, host, errno_to_str(error)); + return NULL; + } + + set_socket_buffer_sizes(sock); + + memset((void*)&localhost, 0, sizeof(localhost)); + + localhost.sun_family = AF_UNIX; + // length checked above + strncpy(localhost.sun_path, host, sizeof(localhost.sun_path)); + +#if defined _WIN32 || defined __SYMBIAN32__ + // For Windows and Symbian, the path needs to be in Unix format + // (the ':' will otherwise delineate the unused port), so convert that back + // to an actual host filename + if (host[0] == '/' && isalpha(host[1]) && host[2] == '/') { + localhost.sun_path[0] = localhost.sun_path[1]; + localhost.sun_path[1] = ':'; + } +#endif + + if (bind(sock, (struct sockaddr *)&localhost, SUN_LEN(&localhost))) { + error = errno; + reason = "bind"; + close(sock); + sock = -1; + } + + if (!error && listen(sock, 16)) { + error = errno; + reason = "listen"; + close(sock); + sock = -1; + } + + if (sock < 0) { + trace(LOG_ALWAYS, "Socket %s error on %s: %s", reason, localhost.sun_path, errno_to_str(error)); + errno = error; + return NULL; + } + + return channel_server_create(ps, sock); +} + + ChannelServer * channel_tcp_server(PeerServer * ps) { int sock; int error; @@ -967,25 +1071,8 @@ errno = error; return NULL; } - si = (ServerTCP *)loc_alloc_zero(sizeof *si); - si->serv.close = server_close; - si->sock = sock; - si->ps = ps; - if (server_list.next == NULL) list_init(&server_list); - if (list_is_empty(&server_list)) { - post_event_with_delay(refresh_all_peer_server, NULL, PEER_DATA_REFRESH_PERIOD * 1000000); - } - list_add_last(&si->servlink, &server_list); - refresh_peer_server(sock, ps); - - si->accreq.done = tcp_server_accept_done; - si->accreq.client_data = si; - si->accreq.type = AsyncReqAccept; - si->accreq.u.acc.sock = sock; - si->accreq.u.acc.addr = &si->addr; - si->accreq.u.acc.addrlen = sizeof(si->addr); - async_req_post(&si->accreq); - return &si->serv; + + return channel_server_create(ps, sock); } typedef struct ChannelConnectInfo { @@ -1005,7 +1092,7 @@ closesocket(info->sock); } else { - ChannelTCP * c = create_channel(info->sock, info->ssl, 0); + ChannelTCP * c = create_channel(info->sock, info->ssl, 0, info->peer_addr.sa_family == AF_UNIX); if (c == NULL) { info->callback(info->callback_args, errno, NULL); closesocket(info->sock); Index: framework/channel_tcp.h =================================================================== --- framework/channel_tcp.h (revision 1284) +++ framework/channel_tcp.h (working copy) @@ -22,10 +22,15 @@ #include /* - * Start TCP channel listener. + * Start TCP (Internet) channel listener. * On error returns NULL and sets errno. */ extern ChannelServer * channel_tcp_server(PeerServer * server); +/* + * Start TCP (Unix domain socket) channel listener. + * On error returns NULL and sets errno. + */ +extern ChannelServer * channel_unix_server(PeerServer * server); /* * Connect client side over TCP. Index: framework/channel.c =================================================================== --- framework/channel.c (revision 1284) +++ framework/channel.c (working copy) @@ -235,6 +235,9 @@ else if (strcmp(transportname, "PIPE") == 0) { return channel_pipe_server(ps); } + else if (strcmp(transportname, "UNIX") == 0) { + return channel_unix_server(ps); + } else { errno = ERR_INV_TRANSPORT; return NULL;