/* Usage: lookup name in the database, send reply back to the requester Return: none */ void lookup_name(int sockfd, int dbfd, int logfd, struct name_prtl *name_request) { int flag, result; char *attr; lock_file(dbfd); write_log(logfd, "[Info] lookup_name -- start to lookup a name in database"); flag = database_lookup(dbfd, name_request->name, &attr); printf("[Info] lookup_name -- search database\n"); if (flag == 0) { // found // send the attribute as the reply data back result = pkt_write(sockfd, 5, name_request->name, attr); } else if (flag == 1) { result = pkt_write(sockfd, 6, name_request->name, "the name is not found"); } else if (flag == -1) { result = pkt_write(sockfd, 8, name_request->name, "fail to read the datebase, please try it later"); } unlock_file(dbfd); write_log(logfd, "[Info] lookup_name -- finish lookup"); if (result < 0) { fprintf(stderr, "[Error] lookup_name -- send reply fail\n"); write_log(logfd, "[Error] lookup_name -- send reply fail"); } else { fprintf(stdout, "[Info] lookup_name -- send reply ok: %s\n", name_request->name); write_log(logfd, "[Info] lookup_name -- send reply ok"); } return; }
/* Usage: add name operation, add the name to database if possible, and send the reply back Return: none */ void add_name(int sockfd, int dbfd, int logfd, struct name_prtl *name_request) { int len, n, flag, result; char *buf; write_log(logfd, "[Info] add_name -- adding name to database"); lock_file(dbfd); /* check wheter a same name is in database, and send reply */ flag = is_in_database(dbfd, name_request->name); printf("[Info] add_name -- finish search database\n"); write_log(logfd, "[Info] add_name -- finish search database"); if (flag == 0) { /* found */ pkt_write(sockfd, 8, name_request->name, "the name is already in database"); return; } else if (flag == -1) { /* fail to search */ pkt_write(sockfd, 8, name_request->name, "fail to read the datebase, please try it later"); return; } /* not find existing name, execute the add operation */ len = strlen(name_request->name) + 2 + strlen(name_request->data); if ((buf = (char*) malloc(len + 1)) == NULL) { perror("[Error] add_name: malloc error"); write_log(logfd, "[Error] add_name: malloc error"); return; } // generate the new line string sprintf(buf, "%s: %s", name_request->name, name_request->data); if ((n = write(dbfd, buf, len)) == -1) { result = pkt_write(sockfd, 8, name_request->name, "fail to add the name pair into database"); } else { result = pkt_write(sockfd, 7, name_request->name, "ok, the name has been added into database"); } unlock_file(dbfd); write_log(logfd, "[Info] add_name: finish adding"); if (result < 0) { fprintf(stderr, "[Error] add_name -- send reply fail\n"); write_log(logfd, "[Error] add_name -- send reply fail"); } else { fprintf(stdout, "[Info] add_name -- send reply ok\n"); write_log(logfd, "[Info] add_name -- send reply ok"); } return; }
void update_name(int sockfd, int dbfd, int logfd, struct name_prtl *name_request) { int len, n, flag, result; char *buf; lock_file(dbfd); write_log(logfd, "[Info] update_name -- start searching the database"); flag = is_in_database(dbfd, name_request->name); printf("[Info] update_name -- finish searching database\n"); if (flag == 0) { /* found */ if (delete_line(dbfd, name_request->name) != 0) { result = pkt_write(sockfd, 8, name_request->name, "fail to operate read or write the database"); } else { /* deleting the old line succeed */ // write a new line to the datebase len = strlen(name_request->name) + 2 + strlen(name_request->data); if ((buf = (char*) malloc(len + 1)) == NULL) { perror("[Error] add_name -- malloc error"); write_log(logfd, "[Error] add_name -- malloc error"); return; } sprintf(buf, "%s: %s", name_request->name, name_request->data); if ((n = write(dbfd, buf, len)) == -1) { result = pkt_write(sockfd, 8, name_request->name, "fail to update the name pair in database"); } else { result = pkt_write(sockfd, 7, name_request->name, "ok, the name pair has been updated"); } } } else if (flag == 1) { result = pkt_write(sockfd, 8, name_request->name, "the name is not found"); } else if (flag == -1) { result = pkt_write(sockfd, 8, name_request->name, "fail to read the datebase, please try it later"); } unlock_file(dbfd); if (result < 0) { fprintf(stderr, "[Error] update_name -- send reply fail\n"); } else { fprintf(stdout, "[Info] update_name -- send reply ok: %s\n", name_request->name); } return; }
/* Usage: delete a name pair from database, send the reply Return: none */ void delete_name(int sockfd, int dbfd, int logfd, struct name_prtl *name_request) { int flag, result; lock_file(dbfd); write_log(logfd, "[Info] delete_name -- start searching the database"); flag = is_in_database(dbfd, name_request->name); printf("[Info] delete_name -- finish searching database\n"); if (flag == 0) { /* found */ if (delete_line(dbfd, name_request->name) != 0) { result = pkt_write(sockfd, 8, name_request->name, "fail to operate read or write the database"); } else { /* delete name pair */ result = pkt_write(sockfd, 7, name_request->name, "delete the name successfully"); } } else if (flag == 1) { /* not find such name */ result = pkt_write(sockfd, 8, name_request->name, "the name is in database"); } else if (flag == -1) { /* error */ result = pkt_write(sockfd, 8, name_request->name, "fail to read the datebase, please try it later"); } unlock_file(dbfd); if (result < 0) { fprintf(stderr, "[Error] delete_name -- send reply fail\n"); write_log(logfd, "[Error] delete_name -- send reply fail"); } else { fprintf(stdout, "[Info] delete_name -- send reply ok: %s\n", name_request->name); write_log(logfd, "[Info] delete_name -- send reply ok"); } return; }
/* Usage: name server main logical func for each server process, receive the pkt and decide what to do Return: none */ void name_server(int sockfd, int dbfd, int itemfd, int rservfd, int logfd, int port) { ssize_t n; int result, i, flag, k, m; char buf[MAXBYTE]; char *data; char hostipaddr[16]; struct name_prtl name_request, name_reply; if ((n = read(sockfd, buf, MAXBYTE)) <= 0) { return; } if (buf[0] == '1') { printf("[Info] receive name request\n"); if ((data = (char *) malloc(n + 1)) == NULL) { perror("malloc error"); return; } for (i = 0; i < n; i ++) { data[i] = buf[i]; } name_request.protocol = 1; if ((result = parse_name_pkt(&name_request, data)) == -1) { fprintf(stderr, "[Error] fail to parse the pkt, invalid format\n"); pkt_write(sockfd, 8, name_request.name, "[Error] unknown pkt"); return; } if (name_request.type > 4 || name_request.type <= 0) { // ignore fprintf(stderr, "[Error] invalid type: %d\n", name_request.type); return; } else { handle_request(&name_request, itemfd, dbfd, rservfd, sockfd, logfd, n, port, data); } } else { fprintf(stderr, "[Error] unknown pkt received\n"); } }
/* Usage: follow the protocol to handle a request, and call right func Return: none */ void handle_request(struct name_prtl *name_request, int itemfd, int dbfd, int rservfd, int sockfd, int logfd, ssize_t n, int port, char *data) { int flag, result, m; char hostipaddr[16]; // chech which server should be responsible for the request flag = is_local(itemfd, name_request->name); if (flag == -1) { /* not have this kind of names */ // ask route server printf("[Info] ask routing server for the name\n"); result = route(rservfd, logfd, name_request->name[0], hostipaddr); if (result == -1) { /* fail */ fprintf(stderr, "[Error] route check failed\n"); write_log(logfd, "[Error] handle_request -- route check failed"); pkt_write(sockfd, 8, name_request->name, "fail to check route table"); } else if (result == 0) { /* new kind of names, add it locally */ // add new mapping first printf("[Info] find the corresponding server\n"); m = add_nameitem(itemfd, name_request->name[0]); if (m == -1) { fprintf(stderr, "[Error] fail to update indextable\n"); write_log(logfd, "[Error] handle_request -- update indextable error"); pkt_write(sockfd, 8, name_request->name, "fail to updata indextable"); } else { if (name_request->type == 2) { /* add new name */ printf("[Info] adding new name: %s\n", name_request->name); add_name(sockfd, dbfd, logfd, name_request); } else if (name_request->type == 1) { /* lookup */ printf("[Info] lookup name: %s\n", name_request->name); lookup_name(sockfd, dbfd, logfd, name_request); } else if (name_request->type == 3) { /* delete */ printf("[Info] delete name: %s\n", name_request->name); delete_name(sockfd, dbfd, logfd, name_request); } else if (name_request->type == 4) { /* update */ printf("[Info] update name: %s\n", name_request->name); update_name(sockfd, dbfd, logfd, name_request); } } } else if (result == 1) { /* there is another server which is responsible for this kind of names */ printf("[Info] forward request\n"); m = forward_request(sockfd, logfd, data, hostipaddr, port, n); if (m == -1) { /* fail */ fprintf(stderr, "[Error] fail to forward request\n"); pkt_write(sockfd, 8, name_request->name, "[Error] fail to forward pkt"); } } } else { /* find this kind of name locally */ if (name_request->type == 2) { /* add new name */ printf("[Info] adding new name: %s\n", name_request->name); add_name(sockfd, dbfd, logfd, name_request); } else if (name_request->type == 1) { /* lookup */ printf("[Info] lookup name: %s\n", name_request->name); lookup_name(sockfd, dbfd, logfd, name_request); } else if (name_request->type == 3) { /* delete */ printf("[Info] delete name: %s\n", name_request->name); delete_name(sockfd, dbfd, logfd, name_request); } else if (name_request->type == 4) { /* update */ printf("[Info] update name: %s\n", name_request->name); update_name(sockfd, dbfd, logfd, name_request); } } }
/* do_control() ** send cmd to list of services given in argv */ void do_control(uchar_t cmd[], char *argv[]){ char pathbuf[256]; size_t n; int fd_conn; int e; /* connect to control socket: */ n = cstr_vlen(basedir, "/", PERP_CONTROL, "/", PERPD_SOCKET); if(!(n < sizeof pathbuf)){ errno = ENAMETOOLONG; fatal_syserr("failure locating perpd control socket ", basedir, "/", PERP_CONTROL, "/", PERPD_SOCKET); } cstr_vcopy(pathbuf, basedir, "/", PERP_CONTROL, "/", PERPD_SOCKET); fd_conn = domsock_connect(pathbuf); if(fd_conn == -1){ if(errno == ECONNREFUSED){ fatal_syserr("perpd not running on control socket ", pathbuf); } else { fatal_syserr("failure connecting to perpd control socket ", pathbuf); } } /* loop through service directory arguments and send control packet: */ for(; *argv != NULL; ++argv){ pkt_t pkt = pkt_INIT(2, 'C', 18); struct stat st; if(stat(*argv, &st) == -1){ ++errs; eputs("error: ", *argv, ": service directory not found"); continue; } if(! S_ISDIR(st.st_mode)){ ++errs; eputs("error: ", *argv, ": not a directory"); continue; } if(!(S_ISVTX & st.st_mode)){ ++errs; eputs("error: ", *argv, ": service directory not activated"); continue; } /* control packet for this directory: */ upak_pack(pkt_data(pkt), "LLbb", (uint64_t)st.st_dev, (uint64_t)st.st_ino, cmd[0], cmd[1]); if(pkt_write(fd_conn, pkt, 0) == -1){ ++errs; eputs_syserr("error: ", *argv, ": error writing request"); continue; } if(pkt_read(fd_conn, pkt, 0) == -1){ ++errs; eputs_syserr("error: ", *argv, ": error reading response"); continue; } if(pkt[0] != 2){ ++errs; eputs("error: ", *argv, ": unknown packet protocol in reply"); continue; } if(pkt[1] != 'E'){ ++errs; eputs("error: ", *argv, ": unknown packet type in reply"); continue; } e = (int)upak32_unpack(&pkt[3]); if(e != 0){ ++errs; errno = e; eputs_syserr("error: ", *argv, ": error reported in reply"); continue; } /* success: */ report(*argv, ": ok"); } return; }
int main(int argc, char *argv[]) { nextopt_t nopt = nextopt_INIT(argc, argv, ":hVb:"); char opt; const char *basedir = NULL; char pathbuf[256]; tain_t now; size_t n; int fd_conn; progname = nextopt_progname(&nopt); while((opt = nextopt(&nopt))){ char optc[2] = {nopt.opt_got, '\0'}; switch(opt){ case 'h': usage(); die(0); break; case 'V': version(); die(0); break; case 'b': basedir = nopt.opt_arg; break; case ':': fatal_usage("missing argument for option -", optc); break; case '?': if(nopt.opt_got != '?'){ fatal_usage("invalid option -", optc); } /* else fallthrough: */ default : die_usage(); break; } } argc -= nopt.arg_ndx; argv += nopt.arg_ndx; if(!*argv){ fatal_usage("missing argument"); } if(!basedir) basedir = getenv("PERP_BASE"); if(!basedir) basedir = "."; if(chdir(basedir) != 0){ fatal_syserr("fail chdir() to ", basedir); } /* connect to control socket: */ n = cstr_vlen(basedir, "/", PERP_CONTROL, "/", PERPD_SOCKET); if(!(n < sizeof pathbuf)){ errno = ENAMETOOLONG; fatal_syserr("failure locating perpd control socket ", basedir, "/", PERP_CONTROL, "/", PERPD_SOCKET); } cstr_vcopy(pathbuf, basedir, "/", PERP_CONTROL, "/", PERPD_SOCKET); fd_conn = domsock_connect(pathbuf); if(fd_conn == -1){ if(errno == ECONNREFUSED){ fatal_syserr("perpd not running on control socket ", pathbuf); }else{ fatal_syserr("failure connecting to perpd control socket ", pathbuf); } } /* uptimes compared to now: */ tain_now(&now); /* loop through service directory arguments and display report: */ for(; *argv != NULL; ++argv){ pkt_t pkt = pkt_INIT(2, 'Q', 16); struct stat st; if(stat(*argv, &st) == -1){ eputs(*argv, ": error: service directory not found"); continue; } if(! S_ISDIR(st.st_mode)){ eputs(*argv, ": error: not a directory"); continue; } if(!(S_ISVTX & st.st_mode)){ vputs(*argv, ": not activated\n"); continue; } upak_pack(pkt_data(pkt), "LL", (uint64_t)st.st_dev, (uint64_t)st.st_ino); if(pkt_write(fd_conn, pkt, 0) == -1){ eputs_syserr("error: ", *argv, ": error writing query"); continue; } if(pkt_read(fd_conn, pkt, 0) == -1){ eputs_syserr("error: ", *argv, ": error reading response"); continue; } if(pkt[0] != 2){ eputs("error: ", *argv, ": unknown packet protocol in reply"); continue; } if(pkt[1] != 'S'){ if(pkt[1] == 'E'){ errno = (int)upak32_unpack(&pkt[3]); eputs_syserr("error: ", *argv, ": error reported in reply"); } else { eputs("error: ", *argv, ": unknown packet type in reply"); } continue; } report(*argv, pkt_data(pkt), &now); } vputs_flush(); die(0); }