Ejemplo n.º 1
0
static int
server_main(pid_t ppid, const char *sockpath)
{
	struct sockaddr_storage name, storage;
	struct sockaddr_un *addr;
	socklen_t namelen;
	int error, level, optname, optval, s, sock;

	sock = socket(PF_LOCAL, SOCK_STREAM, 0);
	if (sock == -1)
		return (1);
	level = SOL_SOCKET;
	optname = SO_REUSEADDR;
	optval = 1;
	if (setsockopt(sock, level, optname, &optval, sizeof(optval)) == -1)
		return (2);
	addr = (struct sockaddr_un *)&storage;
	addr->sun_family = AF_LOCAL;
	strcpy(addr->sun_path, sockpath);
	addr->sun_len = SUN_LEN(addr);
	if (bind(sock, (struct sockaddr *)addr, addr->sun_len) == -1)
		return (3);
	if (listen(sock, 0) == -1)
		return (4);
	if (kill(ppid, SIG) == -1)
		return (5);
	namelen = sizeof(name);
	if ((s = accept(sock, (struct sockaddr *)&name, &namelen)) == -1)
		return (6);

	if (do_recvmsg(s) != 0)
		return (7);

	if (close(s) == -1)
		return (8);
	if (close(sock) == -1)
		return (9);
	if (unlink(sockpath) == -1)
		return (10);

	return (0);
}
Ejemplo n.º 2
0
static int slave(slave_data_init_hnd data_init_hnd, int sock)
{
    sigset_t		sset;
    struct sigaction	sa;
    struct timeval		client_done,
                   client_start,
                   new_client_duration = { NEW_CLIENT_DURATION, 0 };

    void	*clnt_data = NULL;
    int	conn = -1,
        srv = -1,
        req_cnt = 0,
        sockflags,
        h_errno,
        pid, i,
        first_request = 0; /* 1 -> first request from connected client expected */



    if ( (pid = fork()) ) return pid;

#ifdef LB_PROF
    monstartup((u_long)&_start, (u_long)&etext);
#endif

    srandom(getpid()+time(NULL));

    for ( i = 0; i < services_ct; i++ )
        close(services[i].conn);

    sigemptyset(&sset);
    sigaddset(&sset, SIGTERM);
    sigaddset(&sset, SIGINT);
    sigaddset(&sset, SIGUSR1);

    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = catchsig;
    sigaction(SIGUSR1, &sa, NULL);

    if (   (sockflags = fcntl(sock, F_GETFL, 0)) < 0
            || fcntl(sock, F_SETFL, sockflags | O_NONBLOCK) < 0 )
    {
        dprintf(("[%d] fcntl(master_sock): %s\n", getpid(), strerror(errno)));
        if ( !debug ) syslog(LOG_CRIT, "fcntl(master_sock): %m");
        exit(1);
    }

    if ( data_init_hnd && data_init_hnd(&clnt_data) )
        /*
         *	XXX: what if the error remains and master will start new slave
         *	again and again?
         *
         *	Then we are in a deep shit.
         */
        exit(1);

    while ( !die && (req_cnt < set_slave_reqs_max || (conn >= 0 && first_request)))
    {
        fd_set				fds;
        int					max = sock,
                            connflags,
                            newconn = -1,
                            newsrv = -1;

        enum { KICK_DONT = 0, KICK_IDLE, KICK_LOAD, KICK_HANDLER, KICK_COUNT }
        kick_client = KICK_DONT;

        static char * kicks[] = {
            "don't kick",
            "idle client",
            "high load",
            "no request handler",
            "request count limit reached",
        };
        unsigned long		seq;
        struct timeval		now,to;


        FD_ZERO(&fds);
        FD_SET(sock, &fds);
        if ( conn >= 0 ) FD_SET(conn, &fds);
        if ( conn > sock ) max = conn;

        to = set_idle_to;
        sigprocmask(SIG_UNBLOCK, &sset, NULL);
        switch (select(max+1, &fds, NULL, NULL, to.tv_sec >= 0 ? &to : NULL))
        {
        case -1:
            if ( errno != EINTR )
            {
                dprintf(("[%d] select(): %s\n", getpid(), strerror(errno)));
                if ( !debug ) syslog(LOG_CRIT, "select(): %m");
                exit(1);
            }
            continue;

        case 0:
            if ( conn < 0 ) continue;

        default:
            break;
        }
        sigprocmask(SIG_BLOCK, &sset, NULL);

        gettimeofday(&now,NULL);

        if ( conn >= 0 && FD_ISSET(conn, &fds) )
        {
            /*
             *	serve the request
             */
            int		rv;

            dprintf(("[%d] incoming request\n", getpid()));

            if ( !services[srv].on_request_hnd )
            {
                kick_client = KICK_HANDLER;
            } else {
                first_request = 0;
                to = set_request_to;
                if ((rv = services[srv].on_request_hnd(conn,to.tv_sec>=0 ? &to : NULL,clnt_data)) == ENOTCONN) {
                    if (services[srv].on_disconnect_hnd
                            && (rv = services[srv].on_disconnect_hnd(conn,NULL,clnt_data)))
                    {
                        dprintf(("[%d] disconnect handler: %s, terminating\n",getpid(),strerror(rv)));
                        exit(1);
                    }
                    close(conn);
                    conn = -1;
                    srv = -1;
                    dprintf(("[%d] Connection closed\n", getpid()));
                }
                else if (rv > 0) {
                    /*	non-fatal error -> close connection and contiue
                     * XXX: likely to leak resources but can we call on_disconnect_hnd() on error?
                     */
                    close(conn);
                    conn = -1;
                    srv = -1;
                    dprintf(("[%d] %s, connection closed\n",getpid(),strerror(rv)));
                    continue;
                }
                else if ( rv < 0 ) {
                    /*	unknown error -> clasified as FATAL -> kill slave
                     */
                    dprintf(("[%d] %s, terminating\n",getpid(),strerror(-rv)));
                    exit(1);
                }
                else {
                    dprintf(("[%d] request done\n", getpid()));
                    gettimeofday(&client_done, NULL);
                }

                if (!check_timeout(new_client_duration,client_start,now)) continue;

            }
        } else {
            if (conn >= 0 && check_timeout(set_idle_to, client_done, now))
                kick_client = KICK_IDLE;
        }

        if ( (conn < 0 || !first_request) && FD_ISSET(sock, &fds) && req_cnt < set_slave_reqs_max )
        {
            /* Prefer slaves with no connection, then kick idle clients,
             * active ones last. Wait less if we have serviced a request in the meantime.
             * Tuned for HZ=100 timer. */
            if ( conn >= 0 ) usleep( kick_client || FD_ISSET(conn, &fds) ? 11000 : 21000);
            if ( do_recvmsg(sock, &newconn, &seq, &newsrv) ) switch ( errno )
                {
                case EINTR: /* XXX: signals are blocked */
                case EAGAIN:
                    continue;
                default:
                    dprintf(("[%d] recvmsg(): %s\n", getpid(), strerror(errno)));
                    if (!debug) syslog(LOG_CRIT,"recvmsg(): %m\n");
                    exit(1);
                }
            kick_client = KICK_LOAD;
        }

        if (req_cnt >= set_slave_reqs_max && !first_request) kick_client = KICK_COUNT;

        if ( kick_client && conn >= 0 )
        {
            if ( services[srv].on_disconnect_hnd )
                services[srv].on_disconnect_hnd(conn, NULL, clnt_data);
            close(conn);
            conn = -1;
            srv = -1;
            dprintf(("[%d] Connection closed, %s\n", getpid(), kicks[kick_client]));
        }

        if ( newconn >= 0 )
        {
            int	ret;

            conn = newconn;
            srv = newsrv;
            gettimeofday(&client_start, NULL);

            switch ( send(sock, &seq, sizeof(seq), 0) )
            {
            case -1:
                if (debug) perror("send()");
                else syslog(LOG_CRIT, "send(): %m\n");
                exit(1);

            case sizeof(seq):
                break;

            default:
                dprintf(("[%d] send(): incomplete message\n", getpid()));
                exit(1);
            }

            req_cnt++;
            dprintf(("[%d] serving %s connection %lu\n", getpid(),
                     services[srv].id? services[srv].id: "", seq));

            connflags = fcntl(conn, F_GETFL, 0);
            if ( fcntl(conn, F_SETFL, connflags | O_NONBLOCK) < 0 )
            {
                dprintf(("[%d] can't set O_NONBLOCK mode (%s), closing.\n", getpid(), strerror(errno)));
                if ( !debug ) syslog(LOG_ERR, "can't set O_NONBLOCK mode (%s), closing.\n", strerror(errno));
                close(conn);
                conn = srv = -1;
                continue;
            }

            to = set_connect_to;
            if (   services[srv].on_new_conn_hnd
                    && (ret = services[srv].on_new_conn_hnd(conn, to.tv_sec >= 0 ? &to : NULL, clnt_data)) )
            {
                dprintf(("[%d] Connection not estabilished, err = %d.\n", getpid(),ret));
                if ( !debug ) syslog(LOG_ERR, "Connection not estabilished, err = %d.\n",ret);
                close(conn);
                conn = srv = -1;
                if (ret < 0) exit(1);
                continue;
            }
            gettimeofday(&client_done, NULL);
            first_request = 1;
        }
    }

    if ( die )
    {
        dprintf(("[%d] Terminating on signal %d\n", getpid(), die));
        if ( !debug ) syslog(LOG_INFO, "Terminating on signal %d", die);
    }

    if (conn >= 0  && services[srv].on_disconnect_hnd )
        services[srv].on_disconnect_hnd(conn, NULL, clnt_data);

    dprintf(("[%d] Terminating after %d requests\n", getpid(), req_cnt));
    if ( !debug ) syslog(LOG_INFO, "Terminating after %d requests", req_cnt);


    exit(0);
}
Ejemplo n.º 3
0
PUBLIC int uds_ioctl(message *dev_m_in, message *dev_m_out)
{
	int minor;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] uds_ioctl() call_count=%d\n", uds_minor(dev_m_in),
							++call_count);
 	printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->IO_ENDPT, 
							dev_m_in->POSITION);
#endif

	minor = uds_minor(dev_m_in);

	if (uds_fd_table[minor].state != UDS_INUSE) {

		/* attempted to close a socket that hasn't been opened --
		 * something is very wrong :(
		 */
		uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
				(cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);

		return EINVAL;
	}

	/* track the system call we are performing in case it gets cancelled */
	uds_fd_table[minor].call_nr = dev_m_in->m_type;
	uds_fd_table[minor].ioctl = dev_m_in->COUNT;
	uds_fd_table[minor].syscall_done = 0;

	/* setup select(2) framework */
	uds_fd_table[minor].selecting = 0;

	/* update the owner endpoint - yes it's really stored in POSITION */
	uds_fd_table[minor].owner = dev_m_in->POSITION;

	switch (dev_m_in->COUNT) {	/* Handle the ioctl(2) command */

		case NWIOSUDSCONN:

			/* connect to a listening socket -- connect() */
			return do_connect(dev_m_in, dev_m_out);

		case NWIOSUDSACCEPT:

			/* accept an incoming connection -- accept() */
			return do_accept(dev_m_in, dev_m_out);

		case NWIOSUDSBLOG:

			/* set the backlog_size and put the socket into the
			 * listening state -- listen()
			 */
			return do_listen(dev_m_in, dev_m_out);

		case NWIOSUDSTYPE:

			/* set the type for this socket (i.e. 
			 * SOCK_STREAM, SOCK_DGRAM, etc) -- socket()
			 */
			return do_socket(dev_m_in, dev_m_out);

		case NWIOSUDSADDR:

			/* set the address for this socket -- bind() */
			return do_bind(dev_m_in, dev_m_out);

		case NWIOGUDSADDR:

			/* get the address for this socket -- getsockname() */
			return do_getsockname(dev_m_in, dev_m_out);

		case NWIOGUDSPADDR:

			/* get the address for the peer -- getpeername() */
			return do_getpeername(dev_m_in, dev_m_out);

		case NWIOSUDSSHUT:

			/* shutdown a socket for reading, writing, or 
			 * both -- shutdown()
			 */
			return do_shutdown(dev_m_in, dev_m_out);

		case NWIOSUDSPAIR:

			/* connect two sockets -- socketpair() */
			return do_socketpair(dev_m_in, dev_m_out);

		case NWIOGUDSSOTYPE:

			/* get socket type -- getsockopt(SO_TYPE) */
			return do_getsockopt_sotype(dev_m_in, dev_m_out);

		case NWIOGUDSPEERCRED:

			/* get peer endpoint -- getsockopt(SO_PEERCRED) */
			return do_getsockopt_peercred(dev_m_in, dev_m_out);

		case NWIOSUDSTADDR:

			/* set target address -- sendto() */
			return do_sendto(dev_m_in, dev_m_out);

		case NWIOGUDSFADDR:

			/* get from address -- recvfrom() */
			return do_recvfrom(dev_m_in, dev_m_out);

		case NWIOGUDSSNDBUF:

			/* get the send buffer size -- getsockopt(SO_SNDBUF) */
			return do_getsockopt_sndbuf(dev_m_in, dev_m_out);

		case NWIOSUDSSNDBUF:

			/* set the send buffer size -- setsockopt(SO_SNDBUF) */
			return do_setsockopt_sndbuf(dev_m_in, dev_m_out);

		case NWIOGUDSRCVBUF:

			/* get the send buffer size -- getsockopt(SO_SNDBUF) */
			return do_getsockopt_rcvbuf(dev_m_in, dev_m_out);

		case NWIOSUDSRCVBUF:

			/* set the send buffer size -- setsockopt(SO_SNDBUF) */
			return do_setsockopt_rcvbuf(dev_m_in, dev_m_out);

		case NWIOSUDSCTRL:

			/* set the control data -- sendmsg() */
			return do_sendmsg(dev_m_in, dev_m_out);

		case NWIOGUDSCTRL:

			/* set the control data -- recvmsg() */
			return do_recvmsg(dev_m_in, dev_m_out);

		default:

			/* the IOCTL command is not valid for /dev/uds --
			 * this happens a lot and is normal. a lot of 
			 * libc functions determine the socket type with 
			 * IOCTLs. Any not for us simply get a EBADIOCTL
			 * response.
			 */
			uds_fd_table[minor].syscall_done = 1;
			uds_set_reply(dev_m_out, TASK_REPLY,
					dev_m_in->IO_ENDPT, 
					(cp_grant_id_t) dev_m_in->IO_GRANT,
					EBADIOCTL);

			return EBADIOCTL;
	}
}