diff --git a/src/client/sock.c b/src/client/sock.c
index ffabdc1b74add0a1a7d09c0575ccf36a1ef59115..6337ee6bf8cd8bf71611a42469b55527b7b84ff8 100644 (file)
--- a/src/client/sock.c
+++ b/src/client/sock.c
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
#include "client/sock.h"
+#include "utils/error.h"
#include "utils/strbuf.h"
#include "utils/proto.h"
struct sdb_client {
char *address;
int fd;
+ _Bool eof;
};
/*
struct sockaddr_un sa;
client->fd = socket(AF_UNIX, SOCK_STREAM, /* protocol = */ 0);
- if (client->fd < 0)
+ if (client->fd < 0) {
+ char errbuf[1024];
+ sdb_log(SDB_LOG_ERR, "Failed to open socket: %s",
+ sdb_strerror(errno, errbuf, sizeof(errbuf)));
return -1;
+ }
sa.sun_family = AF_UNIX;
strncpy(sa.sun_path, address, sizeof(sa.sun_path));
sa.sun_path[sizeof(sa.sun_path) - 1] = '\0';
if (connect(client->fd, (struct sockaddr *)&sa, sizeof(sa))) {
+ char errbuf[1024];
sdb_client_close(client);
+ sdb_log(SDB_LOG_ERR, "Failed to connect to '%s': %s",
+ sa.sun_path, sdb_strerror(errno, errbuf, sizeof(errbuf)));
return -1;
}
return client->fd;
return NULL;
client = malloc(sizeof(*client));
- if (! client)
+ if (! client) {
+ sdb_log(SDB_LOG_ERR, "Out of memory");
return NULL;
+ }
memset(client, 0, sizeof(*client));
client->fd = -1;
+ client->eof = 1;
client->address = strdup(address);
if (! client->address) {
sdb_client_destroy(client);
+ sdb_log(SDB_LOG_ERR, "Out of memory");
return NULL;
}
} /* sdb_client_destroy */
int
-sdb_client_connect(sdb_client_t *client)
+sdb_client_connect(sdb_client_t *client, const char *username)
{
+ sdb_strbuf_t *buf;
+ ssize_t status;
+ uint32_t rstatus;
+
if ((! client) || (! client->address))
return -1;
connect_unixsock(client, client->address + strlen("unix:"));
else if (*client->address == '/')
connect_unixsock(client, client->address);
- else
+ else {
+ sdb_log(SDB_LOG_ERR, "Unknown address type: %s", client->address);
return -1;
+ }
if (client->fd < 0)
return -1;
- return 0;
+ client->eof = 0;
+
+ /* XXX */
+ if (! username)
+ username = "";
+
+ status = sdb_client_send(client, CONNECTION_STARTUP,
+ (uint32_t)strlen(username), username);
+ if (status < 0) {
+ char errbuf[1024];
+ sdb_client_close(client);
+ sdb_log(SDB_LOG_ERR, "Failed to send STARTUP message to server: %s",
+ sdb_strerror(errno, errbuf, sizeof(errbuf)));
+ return (int)status;
+ }
+
+ buf = sdb_strbuf_create(64);
+ rstatus = 0;
+ status = sdb_client_recv(client, &rstatus, buf);
+ if ((status > 0) && (rstatus == CONNECTION_OK))
+ return 0;
+
+ if (status < 0) {
+ char errbuf[1024];
+ sdb_log(SDB_LOG_ERR, "Failed to receive server response: %s",
+ sdb_strerror(errno, errbuf, sizeof(errbuf)));
+ }
+ else if (client->eof)
+ sdb_log(SDB_LOG_ERR, "Encountered end-of-file while waiting "
+ "for server response");
+
+ if (rstatus != CONNECTION_OK) {
+ sdb_log(SDB_LOG_ERR, "Access denied for user '%s'", username);
+ status = -((int)rstatus);
+ }
+
+ sdb_client_close(client);
+ sdb_strbuf_destroy(buf);
+ return (int)status;
} /* sdb_client_connect */
+int
+sdb_client_sockfd(sdb_client_t *client)
+{
+ if (! client)
+ return -1;
+ return client->fd;
+} /* sdb_client_sockfd */
+
void
sdb_client_close(sdb_client_t *client)
{
close(client->fd);
client->fd = -1;
+ client->eof = 1;
} /* sdb_client_close */
ssize_t
size_t data_offset = sdb_strbuf_len(buf);
+ if (code)
+ *code = UINT32_MAX;
+
if ((! client) || (! client->fd) || (! buf)) {
errno = EBADF;
return -1;
}
- if (code)
- *code = UINT32_MAX;
-
while (42) {
ssize_t status;
+ if (sdb_proto_select(client->fd, SDB_PROTO_SELECTIN))
+ return -1;
+
errno = 0;
status = sdb_strbuf_read(buf, client->fd, req);
if (status < 0) {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
- break;
+ continue;
return status;
}
- else if (! status) /* EOF */
+ else if (! status) {
+ client->eof = 1;
break;
+ }
total += (size_t)status;
break;
}
+ if (total != req) {
+ /* unexpected EOF; clear partially read data */
+ sdb_strbuf_skip(buf, data_offset, sdb_strbuf_len(buf));
+ return 0;
+ }
+
+ if (rstatus != UINT32_MAX)
+ /* remove status,len */
+ sdb_strbuf_skip(buf, data_offset, 2 * sizeof(rstatus));
+
if (code)
*code = rstatus;
return (ssize_t)total;
} /* sdb_client_recv */
+_Bool
+sdb_client_eof(sdb_client_t *client)
+{
+ if ((! client) || (client->fd < 0))
+ return 1;
+ return client->eof;
+} /* sdb_client_eof */
+
/* vim: set tw=78 sw=4 ts=4 noexpandtab : */