And don't keep global state: it's messy, and you can never invoke two of them.
+ * Ccanlint:
+ * // hack to make valgrind show the error. FIXME!
+ * tests_pass_valgrind --child-silent-after-fork=no
+ *
* Example:
* #include <sys/types.h>
* #include <sys/socket.h>
* Example:
* #include <sys/types.h>
* #include <sys/socket.h>
printf("ccan/read_write_all\n");
printf("ccan/str\n");
printf("ccan/foreach\n");
printf("ccan/read_write_all\n");
printf("ccan/str\n");
printf("ccan/foreach\n");
- printf("ccan/noerr\n");
printf("ccan/failtest\n");
printf("ccan/opt\n");
printf("ccan/array_size\n");
printf("ccan/failtest\n");
printf("ccan/opt\n");
printf("ccan/array_size\n");
#include <ccan/opt/opt.h>
#include <ccan/tevent/tevent.h>
#include <ccan/array_size/array_size.h>
#include <ccan/opt/opt.h>
#include <ccan/tevent/tevent.h>
#include <ccan/array_size/array_size.h>
-#include <ccan/noerr/noerr.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
char *question;
/* How many bytes of the reply we sent so far. */
size_t bytes_sent;
char *question;
/* How many bytes of the reply we sent so far. */
size_t bytes_sent;
+ /* Our server. */
+ struct oserver *oserver;
-/* 5 clients should be enough for anybody! */
-static struct client *clients[5];
-static int sfd;
-static struct tevent_fd *sfde;
+struct oserver {
+ /* 5 clients should be enough for anybody! */
+ struct client *clients[5];
+ int fd;
+ struct tevent_fd *fde;
+};
static ssize_t write_string(int fd, const char *str)
{
static ssize_t write_string(int fd, const char *str)
{
- for (i = 0; i < ARRAY_SIZE(clients); i++) {
- if (clients[i] == client) {
- clients[i] = NULL;
- tevent_fd_set_flags(sfde, TEVENT_FD_READ);
+ for (i = 0; i < ARRAY_SIZE(client->oserver->clients); i++) {
+ if (client->oserver->clients[i] == client) {
+ client->oserver->clients[i] = NULL;
+ tevent_fd_set_flags(client->oserver->fde,
+ TEVENT_FD_READ);
}
static void add_client(struct tevent_context *ev,
}
static void add_client(struct tevent_context *ev,
- struct tevent_fd *fde, uint16_t flags, void *unused)
+ struct tevent_fd *fde, uint16_t flags, void *_oserver)
+ struct oserver *oserver = _oserver;
struct client *client;
unsigned int i;
struct client *client;
unsigned int i;
- client = talloc(sfde, struct client);
- client->fd = accept(sfd, NULL, 0);
+ client = talloc(oserver, struct client);
+ client->fd = accept(oserver->fd, NULL, 0);
if (client->fd < 0)
err(1, "Accepting client connection");
client->state = RECEIVING_USER_QUESTION;
client->bytes_sent = 0;
client->question = talloc_strdup(client, "");
if (client->fd < 0)
err(1, "Accepting client connection");
client->state = RECEIVING_USER_QUESTION;
client->bytes_sent = 0;
client->question = talloc_strdup(client, "");
+ client->oserver = oserver;
client->fde = tevent_add_fd(ev, client, client->fd,
state_flag_map[client->state],
service_client, client);
tevent_fd_set_auto_close(client->fde);
/* Find empty slot in array for this client. */
client->fde = tevent_add_fd(ev, client, client->fd,
state_flag_map[client->state],
service_client, client);
tevent_fd_set_auto_close(client->fde);
/* Find empty slot in array for this client. */
- for (i = 0; clients[i]; i++);
- clients[i] = client;
+ for (i = 0; oserver->clients[i]; i++);
+ oserver->clients[i] = client;
talloc_set_destructor(client, cleanup_client);
/* Full? Stop listening... */
talloc_set_destructor(client, cleanup_client);
/* Full? Stop listening... */
- if (i == ARRAY_SIZE(clients)-1)
- tevent_fd_set_flags(sfde, 0);
+ if (i == ARRAY_SIZE(oserver->clients)-1)
+ tevent_fd_set_flags(oserver->fde, 0);
+}
+
+static int destroy_oserver(struct oserver *oserver)
+{
+ close(oserver->fd);
+ return 0;
-void *oserver_setup(struct tevent_context *ev, unsigned short port)
+struct oserver *oserver_setup(struct tevent_context *ev, unsigned short port)
+ struct oserver *oserver;
int one = 1;
union {
struct sockaddr addr;
struct sockaddr_in in;
} u;
int one = 1;
union {
struct sockaddr addr;
struct sockaddr_in in;
} u;
- sfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (sfd < 0)
- return false;
+ oserver = talloc(ev, struct oserver);
+
+ oserver->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (oserver->fd < 0) {
+ talloc_free(oserver);
+ return NULL;
+ }
+ talloc_set_destructor(oserver, destroy_oserver);
- if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)))
+ if (setsockopt(oserver->fd, SOL_SOCKET, SO_REUSEADDR,
+ &one, sizeof(one)))
warn("Setting socket reuse");
u.in.sin_family = AF_INET;
u.in.sin_port = htons(port);
u.in.sin_addr.s_addr = INADDR_ANY;
warn("Setting socket reuse");
u.in.sin_family = AF_INET;
u.in.sin_port = htons(port);
u.in.sin_addr.s_addr = INADDR_ANY;
- if (bind(sfd, &u.addr, sizeof(u.in)) == -1) {
- close_noerr(sfd);
+ if (bind(oserver->fd, &u.addr, sizeof(u.in)) == -1) {
+ talloc_free(oserver);
- if (listen(sfd, 0) != 0) {
- close_noerr(sfd);
+ if (listen(oserver->fd, 0) != 0) {
+ talloc_free(oserver);
- sfde = tevent_add_fd(ev, ev, sfd, TEVENT_FD_READ, add_client, NULL);
- tevent_fd_set_auto_close(sfde);
+ oserver->fde = tevent_add_fd(ev, oserver, oserver->fd,
+ TEVENT_FD_READ, add_client, oserver);
+ if (!oserver->fde) {
+ talloc_free(oserver);
+ return NULL;
+ }
/* Don't kill us if client dies. */
signal(SIGPIPE, SIG_IGN);
/* Don't kill us if client dies. */
signal(SIGPIPE, SIG_IGN);
* @port: port to use (usually OSERVER_PORT)
*
* Opens a socket and binds it to @port, then sets it up to listen
* @port: port to use (usually OSERVER_PORT)
*
* Opens a socket and binds it to @port, then sets it up to listen
- * for connections. talloc_free() the pointer returned to shut it down.
+ * for connections. talloc_free() the pointer returned to shut it down
+ * (its parent is the tevent_context).
+ * struct oserver *oserver;
* struct tevent_context *ev;
*
* ev = tevent_context_init(NULL);
* struct tevent_context *ev;
*
* ev = tevent_context_init(NULL);
* while (tevent_loop_wait(ev) == 0);
* err(1, "Event loop failed");
*/
* while (tevent_loop_wait(ev) == 0);
* err(1, "Event loop failed");
*/
-void *oserver_setup(struct tevent_context *ev, unsigned short port);
+struct oserver *oserver_setup(struct tevent_context *ev, unsigned short port);
#define OSERVER_PORT 2727
#endif /* CCAN_OSERVER_H */
#define OSERVER_PORT 2727
#endif /* CCAN_OSERVER_H */