1 /*
2 * SysDB - src/frontend/connection.c
3 * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
28 #include "sysdb.h"
29 #include "core/error.h"
30 #include "frontend/connection.h"
31 #include "utils/strbuf.h"
33 #include <assert.h>
34 #include <errno.h>
36 #include <arpa/inet.h>
38 #include <string.h>
40 /*
41 * connection handler functions
42 */
44 static uint32_t
45 connection_get_int32(sdb_conn_t *conn, size_t offset)
46 {
47 const char *data;
48 uint32_t n;
50 assert(conn && (sdb_strbuf_len(conn->buf) >= offset + sizeof(uint32_t)));
52 data = sdb_strbuf_string(conn->buf);
53 memcpy(&n, data + offset, sizeof(n));
54 n = ntohl(n);
55 return n;
56 } /* connection_get_int32 */
58 static int
59 command_handle(sdb_conn_t *conn)
60 {
61 assert(conn && conn->cmd && conn->cmd_len);
62 /* XXX */
63 sdb_strbuf_skip(conn->buf, conn->cmd_len);
64 conn->cmd = conn->cmd_len = 0;
65 return 0;
66 } /* command_handle */
68 /* initialize the connection state information */
69 static int
70 command_init(sdb_conn_t *conn)
71 {
72 assert(conn && (! conn->cmd) && (! conn->cmd_len));
74 conn->cmd = connection_get_int32(conn, 0);
75 conn->cmd_len = connection_get_int32(conn, sizeof(uint32_t));
76 sdb_strbuf_skip(conn->buf, 2 * sizeof(uint32_t));
77 return 0;
78 } /* command_init */
80 /* returns negative value on error, 0 on EOF, number of octets else */
81 static ssize_t
82 connection_read(sdb_conn_t *conn)
83 {
84 ssize_t n = 0;
86 while (42) {
87 ssize_t status;
89 errno = 0;
90 status = sdb_strbuf_read(conn->buf, conn->fd, 1024);
91 if (status < 0) {
92 if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
93 break;
94 return (int)status;
95 }
96 else if (! status) /* EOF */
97 break;
99 n += status;
100 }
102 return n;
103 } /* connection_read */
105 /*
106 * public API
107 */
109 int
110 sdb_connection_init(sdb_conn_t *conn)
111 {
112 if (conn->buf) {
113 sdb_log(SDB_LOG_WARNING, "frontend: Attempted to re-initialize "
114 "a frontend connection");
115 return -1;
116 }
118 conn->buf = sdb_strbuf_create(/* size = */ 128);
119 if (! conn->buf) {
120 sdb_log(SDB_LOG_ERR, "frontend: Failed to allocate a read buffer "
121 "for a new connection");
122 sdb_connection_close(conn);
123 return -1;
124 }
126 conn->cmd = conn->cmd_len = 0;
127 conn->fd = -1;
128 return 0;
129 } /* sdb_connection_init */
131 void
132 sdb_connection_close(sdb_conn_t *conn)
133 {
134 size_t len;
136 if (conn->buf) {
137 len = sdb_strbuf_len(conn->buf);
138 if (len)
139 sdb_log(SDB_LOG_INFO, "frontend: Discarding incomplete command "
140 "(%zu byte%s left in buffer)", len, len == 1 ? "" : "s");
141 }
143 sdb_log(SDB_LOG_DEBUG, "frontend: Closing connection on fd=%i",
144 conn->fd);
145 close(conn->fd);
146 conn->fd = -1;
148 sdb_strbuf_destroy(conn->buf);
149 conn->buf = NULL;
150 } /* sdb_connection_fini */
152 ssize_t
153 sdb_connection_read(sdb_conn_t *conn)
154 {
155 ssize_t n = 0;
157 while (42) {
158 ssize_t status = connection_read(conn);
160 if ((! conn->cmd) && (! conn->cmd_len)
161 && (sdb_strbuf_len(conn->buf) >= 2 * sizeof(int32_t)))
162 command_init(conn);
163 if (conn->cmd_len && (sdb_strbuf_len(conn->buf) >= conn->cmd_len))
164 command_handle(conn);
166 if (status <= 0)
167 break;
169 n += status;
170 }
171 return n;
172 } /* sdb_connection_read */
174 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */