/* *This is the root component of the SqueakEasy. *[Implementation] * * Copyright 2003 Joseph Pingenot This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * */ #include #include #include #include #include #include #include #include #include #include #include "squeakyroot.h" #include "squeakyroot-internal.h" #include "netcmd.h" #include "localcmd.h" #include "readline.h" extern int errno; /*Alright. First off, our internal function definitions*/ /*Initialization routine*/ int init_squeakyroot(void); /*handle network traffic*/ void handle_netlink(int fd); void handle_lcllink(int fd); /*Global args*/ int so_local; /*Local socket to listen to service providers.*/ int so_net; /*Network socket to listen in for requests*/ /*The main function*/ int main(int argc, char *argv[]){ int err; struct sockaddr_un *saddr_local = (struct sockaddr_un*) malloc(sizeof(struct sockaddr_un)); struct sockaddr_in *saddr_net = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in)); socklen_t local_saddlen; socklen_t net_saddlen; /*for select()*/ fd_set fds; int connfd; int retval; int topfd; if((saddr_local == NULL) || (saddr_net == NULL)){ fprintf(stderr, "squeakyroot.main(): could not allocate local and network addresses. Exitin.\n"); return SQKEZ_ENOSADDR; } /*First, initialize*/ err = init_squeakyroot(); if(err){ fprintf(stderr, "squeakyroot.main(): failed to initialize squeakyroot. Exiting.\n"); return SQKEZ_EINIT; } /*Set up our fds*/ FD_ZERO(&fds); FD_SET(so_local, &fds); FD_SET(so_net, &fds); /*Top file descriptor, for select*/ topfd = (so_local > so_net)? so_local + 1 : so_net + 1; while(1){ /*Can we get a message? This will block if we can't.*/ err = select(topfd, &fds, NULL, NULL, NULL); if(err < 0){ /*Error occurred.*/ perror("squeakyroot.main(): select() failed!\n"); /*Loop around and try it again!*/ continue; } /*Alright. Which fd is ready for reading?*/ if(FD_ISSET(so_local, &fds)){ printf("got local request\n"); /*Accept the connection*/ connfd = accept(so_local, (struct sockaddr*)saddr_local, &local_saddlen); if(connfd < 0){ perror("squeakyroot.main(): accept(so_local) failed!"); continue; } /*For now, just use the netlink*/ handle_netlink(connfd); close(connfd); }else if(FD_ISSET(so_net, &fds)){ printf("got network request\n"); /*Accept the connection*/ connfd = accept(so_net, (struct sockaddr*)saddr_net, &net_saddlen); if(connfd < 0){ perror("squeakyroot.main(): accept(so_net) failed!"); continue; } /*Read in the data. A child process will handle this.*/ handle_netlink(connfd); /*And close our fd on the link*/ close(connfd); }else{ /*Timer just expired. We don't need to do anything, so just continue.*/ printf("timer expired?! We don't *have* a timer!!\n"); continue; } } return 0; } /*Initializes squeakyroot *ARGS: * none *RETURNS * 0 success * 1 unable to open a local unix domain socket * 2 unable to get a new sockaddr_un struct * 3 couldn't bind local socket * 4 couldn't open tcp socket * 5 couldn't create new sockaddr_in struct * 6 couldn't bind tcp socket * 7 couldn't listen to local socket * 8 couldn't lisetn to network socket */ int init_squeakyroot(void){ int err; struct sockaddr_un *saddr_local = (struct sockaddr_un*) malloc(sizeof(struct sockaddr_un)); struct sockaddr_in *saddr_net = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in)); /*First, open up our local socket to start taking registrations.*/ so_local = socket(AF_UNIX, SOCK_STREAM, 0); if(so_local < 0){ return 1; } /*We're going to pass creds across this sometimes, so set it up*/ //setsockopt(so_local, SO_PASSCRED); /*Bind the socket*/ if(saddr_local == NULL) return 2; saddr_local->sun_family = AF_UNIX; strcpy(saddr_local->sun_path, SQKEZ_ROOTSOCKNAME); err = bind(so_local, (struct sockaddr*)saddr_local, sizeof(struct sockaddr_un)); if(err < 0){ fprintf(stderr, "squeakyroot.init_squeakyroot(): error %d (%s) occurred while binding local socket %s.\n", errno, strerror(errno), SQKEZ_ROOTSOCKNAME); return 3; } err = listen(so_local, 32); if(err < 0){ fprintf(stderr, "squeakyroot.queakyrootinit(): error %d listening to local socket (%s)\n", errno, strerror(errno)); return 7; } /*Now open up our network tcp socket*/ so_net = socket(AF_INET, SOCK_STREAM, 0); if(so_net < 0){ return 4; } /*Set our sockopts, if desired.*/ // if(saddr_net == NULL) return 5; saddr_net->sin_family = AF_INET; saddr_net->sin_port = htons(SQKEZ_TCPPORT); /*This had better be valid, or there's an OS bug. Not even gonna check it*/ saddr_net->sin_addr.s_addr = INADDR_ANY; /*Bind!*/ err = bind(so_net, (struct sockaddr*)saddr_net, sizeof(struct sockaddr_in)); if(err < 0){ fprintf(stderr, "squeakyroot.init_squeakyroot(): error %d (%s) occurred while binding net socket for TCP port %d (any address).\n", errno, strerror(errno), SQKEZ_TCPPORT); return 6; } /*Listen.*/ err = listen(so_net, 32); if(err < 0){ fprintf(stderr, "squeakyroot.main(): error %d listening to net socket (%s)\n", errno, strerror(errno)); return 8; } return 0; } /*Handles traffic from the network, once the connection's been accepted *ARGS: * file descriptor to read from. *RETURNS: * nothing */ void handle_netlink(int fd){ char *line; /*The line we just read off the network.*/ long int linelen; /*The length of the line (including terminating zero) * Does NOT include the ending newline.*/ int cmd_type; /*Result of processing a line.*/ int proto; /*protocol version*/ /*First, fork us off.*/ if(fork()){ /*We're the parent (child gets returned 0). Just return; child handles the link now.*/ return; } /*Open the discussion. This takes care of opening up the conversation and * getting ready to process the subject's requests*/ proto = do_subject_pleasantries(fd); printf("got proto %d\n", proto); if(proto == SQKRT_SUBJ_BADPROTO){ /*The subject committed a faux pas! Goodbye!*/ nak_subj_proto(proto, fd); close(fd); /*We then also exit, to terminate the connection.*/ exit(1); }else if(!subjectproto_isvalid(proto)){ /*The subject is talking a dialect we don't understand. *Politely close off the connection.*/ nak_subj_proto(proto, fd); close(fd); exit(2); } while((line = readline(fd, &linelen)) != NULL){ /*This is our dispatch loop. We receive requests and then act on them.*/ cmd_type = get_subj_cmd(proto, line, linelen); printf("got command %d from line \"%s\"\n", cmd_type, line); /*As the second part of this if statement, we process the request. * It's possible that the connection may be terminated, and we want to * catch that. */ if((cmd_type == SQKRT_SUBJ_QUIT) || (process_subj_cmd(proto, cmd_type, fd) == SQKRT_SUBJ_QUIT)){ /*User wants to quit*/ ack_subj_quit(proto, fd); /*Close the fd and quit normally*/ close(fd); exit(0); } } printf("exited top-level while\n"); close(fd); exit(0); } /*Handles traffic from the local socket, once the connection's been accepted *ARGS: * file descriptor to read from. *RETURNS: * nothing */ void handle_lcllink(int fd){ /*Data holding info*/ /*First, fork us off.*/ if(fork()){ //printf("parent going back\n"); /*We're the parent (child gets returned 0). Just return; child handles the link now.*/ return; } close(fd); exit(0); }