version 1.48, 2011/03/03 08:51:47 |
version 1.49, 2012/03/09 09:57:40 |
|
|
enum msgtype client_exittype; |
enum msgtype client_exittype; |
int client_attached; |
int client_attached; |
|
|
|
int client_get_lock(char *); |
int client_connect(char *, int); |
int client_connect(char *, int); |
void client_send_identify(int); |
void client_send_identify(int); |
void client_send_environ(void); |
void client_send_environ(void); |
|
|
int client_dispatch_attached(void); |
int client_dispatch_attached(void); |
int client_dispatch_wait(void *); |
int client_dispatch_wait(void *); |
|
|
|
/* |
|
* Get server create lock. If already held then server start is happening in |
|
* another client, so block until the lock is released and return -1 to |
|
* retry. Ignore other errors - just continue and start the server without the |
|
* lock. |
|
*/ |
|
int |
|
client_get_lock(char *lockfile) |
|
{ |
|
int lockfd; |
|
|
|
if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1) |
|
fatal("open failed"); |
|
|
|
if (flock(lockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) { |
|
while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR) |
|
/* nothing */; |
|
close(lockfd); |
|
return (-1); |
|
} |
|
|
|
return (lockfd); |
|
} |
|
|
/* Connect client to server. */ |
/* Connect client to server. */ |
int |
int |
client_connect(char *path, int start_server) |
client_connect(char *path, int start_server) |
{ |
{ |
struct sockaddr_un sa; |
struct sockaddr_un sa; |
size_t size; |
size_t size; |
int fd; |
int fd, lockfd; |
|
char *lockfile; |
|
|
memset(&sa, 0, sizeof sa); |
memset(&sa, 0, sizeof sa); |
sa.sun_family = AF_UNIX; |
sa.sun_family = AF_UNIX; |
|
|
return (-1); |
return (-1); |
} |
} |
|
|
|
retry: |
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) |
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) |
fatal("socket failed"); |
fatal("socket failed"); |
|
|
if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { |
if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { |
|
if (errno != ECONNREFUSED && errno != ENOENT) |
|
goto failed; |
if (!start_server) |
if (!start_server) |
goto failed; |
goto failed; |
switch (errno) { |
close(fd); |
case ECONNREFUSED: |
|
if (unlink(path) != 0) |
xasprintf(&lockfile, "%s.lock", path); |
goto failed; |
if ((lockfd = client_get_lock(lockfile)) == -1) |
/* FALLTHROUGH */ |
goto retry; |
case ENOENT: |
if (unlink(path) != 0 && errno != ENOENT) |
if ((fd = server_start()) == -1) |
return (-1); |
goto failed; |
fd = server_start(lockfd, lockfile); |
break; |
xfree(lockfile); |
default: |
close(lockfd); |
goto failed; |
|
} |
|
} |
} |
|
|
setblocking(fd, 0); |
setblocking(fd, 0); |