master.c revision 25757faf029c369a8318349dafe952e2358df1d8
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro/* Copyright (C) 2002 Timo Sirainen */
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro#include "common.h"
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro#include "hash.h"
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro#include "ioloop.h"
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro#include "network.h"
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro#include "fdpass.h"
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro#include "master.h"
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro#include "client.h"
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro#include <unistd.h>
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbelorostatic struct io *io_master;
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbelorostatic struct hash_table *master_requests;
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbelorostatic unsigned int master_pos;
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbelorostatic char master_buf[sizeof(struct master_login_reply)];
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbelorostatic void request_handle(struct master_login_reply *reply)
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro{
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro struct client *client;
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro client = hash_lookup(master_requests, POINTER_CAST(reply->tag));
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro if (client == NULL)
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro i_fatal("Master sent reply with unknown tag %u", reply->tag);
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro client->master_callback(client, reply->success);
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro hash_remove(master_requests, POINTER_CAST(reply->tag));
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro}
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbelorovoid master_request_imap(struct client *client, master_callback_t *callback,
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro unsigned int auth_pid, unsigned int auth_id)
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro{
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro struct master_login_request req;
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro memset(&req, 0, sizeof(req));
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro req.tag = client->fd;
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro req.auth_pid = auth_pid;
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro req.auth_id = auth_id;
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro req.ip = client->ip;
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro if (fd_send(LOGIN_MASTER_SOCKET_FD,
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro client->fd, &req, sizeof(req)) != sizeof(req))
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro i_fatal("fd_send() failed: %m");
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro client->master_callback = callback;
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro hash_insert(master_requests, POINTER_CAST(req.tag), client);
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro}
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbelorovoid master_notify_finished(void)
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro{
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro struct master_login_request req;
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro if (io_master == NULL)
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro return;
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro memset(&req, 0, sizeof(req));
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro /* sending -1 as fd does the notification */
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro if (fd_send(LOGIN_MASTER_SOCKET_FD,
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro -1, &req, sizeof(req)) != sizeof(req))
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro i_fatal("fd_send() failed: %m");
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro}
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbelorovoid master_close(void)
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro{
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro if (io_master == NULL)
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro return;
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro clients_destroy_all();
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro if (close(LOGIN_MASTER_SOCKET_FD) < 0)
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro i_fatal("close(master) failed: %m");
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro io_remove(io_master);
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro io_master = NULL;
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro main_close_listen();
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro main_unref();
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro}
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbelorostatic void master_input(void *context __attr_unused__, int fd,
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro struct io *io __attr_unused__)
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro{
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro int ret;
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro
d58fda4376e4bf67072ce2e69f6f47036f9dbb68jbeloro ret = net_receive(fd, master_buf + master_pos,
sizeof(master_buf) - master_pos);
if (ret < 0) {
/* master died, kill all clients logging in */
master_close();
return;
}
master_pos += ret;
if (master_pos < sizeof(master_buf))
return;
/* reply is now read */
request_handle((struct master_login_reply *) master_buf);
master_pos = 0;
}
void master_init(void)
{
main_ref();
master_requests = hash_create(default_pool, default_pool,
0, NULL, NULL);
master_pos = 0;
io_master = io_add(LOGIN_MASTER_SOCKET_FD, IO_READ, master_input, NULL);
/* just a note to master that we're ok. if we die before,
master should shutdown itself. */
master_notify_finished();
}
void master_deinit(void)
{
hash_destroy(master_requests);
if (io_master != NULL)
io_remove(io_master);
}