Code

frontend: Moved connection init/close to connection.c.
[sysdb.git] / src / frontend / connection.c
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)
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)
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)
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 : */