static struct async *setup_async(void) { struct async *as; fail_unless((as=async_alloc())!=NULL); as->init(as, 0 /* estimate */); return as; }
int status_client_ncurses(struct conf **confs) { int ret=-1; int csin=-1; int csout=-1; pid_t childpid=-1; struct async *as=NULL; const char *monitor_logfile=get_string(confs[OPT_MONITOR_LOGFILE]); struct asfd *so_asfd=NULL; struct sel *sel=NULL; if(!(sel=sel_alloc())) goto end; setup_signals(); // Fork a burp child process that will contact the server over SSL. // We will read and write from and to its stdout and stdin. if((childpid=fork_monitor(&csin, &csout, confs))<0) goto end; //printf("childpid: %d\n", childpid); if(!(as=async_alloc()) || as->init(as, 0) || !setup_asfd_linebuf_write(as, "monitor stdin", &csin) || !setup_asfd_linebuf_read(as, "monitor stdout", &csout)) goto end; //printf("ml: %s\n", monitor_logfile); #ifdef HAVE_NCURSES if(actg==ACTION_STATUS) { if(!setup_asfd_ncurses_stdin(as)) goto end; ncurses_init(); } #endif if(!(so_asfd=setup_asfd_stdout(as))) goto end; if(monitor_logfile && !(lfzp=fzp_open(monitor_logfile, "wb"))) goto end; log_fzp_set_direct(lfzp); ret=status_client_ncurses_main_loop(as, so_asfd, sel, get_string(confs[OPT_ORIG_CLIENT])); end: #ifdef HAVE_NCURSES if(actg==ACTION_STATUS) ncurses_free(); #endif if(ret) logp("%s exiting with error: %d\n", __func__, ret); fzp_close(&lfzp); async_asfd_free_all(&as); close_fd(&csin); close_fd(&csout); sel_free(&sel); return ret; }
int champ_chooser_server(struct sdirs *sdirs, struct conf **confs, int resume) { int s; int ret=-1; int len; struct asfd *asfd=NULL; struct sockaddr_un local; struct lock *lock=NULL; struct async *as=NULL; int started=0; struct scores *scores=NULL; const char *directory=get_string(confs[OPT_DIRECTORY]); if(!(lock=lock_alloc_and_init(sdirs->champlock)) || build_path_w(sdirs->champlock)) goto end; lock_get(lock); switch(lock->status) { case GET_LOCK_GOT: log_fzp_set(sdirs->champlog, confs); logp("Got champ lock for dedup_group: %s\n", get_string(confs[OPT_DEDUP_GROUP])); break; case GET_LOCK_NOT_GOT: case GET_LOCK_ERROR: default: //logp("Did not get champ lock\n"); goto end; } if((s=socket(AF_UNIX, SOCK_STREAM, 0))<0) { logp("socket error in %s: %s\n", __func__, strerror(errno)); goto end; } memset(&local, 0, sizeof(struct sockaddr_un)); local.sun_family=AF_UNIX; snprintf(local.sun_path, sizeof(local.sun_path), "%s", sdirs->champsock); len=strlen(local.sun_path)+sizeof(local.sun_family)+1; unlink(sdirs->champsock); if(bind(s, (struct sockaddr *)&local, len)<0) { logp("bind error in %s: %s\n", __func__, strerror(errno)); goto end; } if(listen(s, 5)<0) { logp("listen error in %s: %s\n", __func__, strerror(errno)); goto end; } if(!(as=async_alloc()) || as->init(as, 0) || !(asfd=setup_asfd(as, "champ chooser main socket", &s, /*listen*/""))) goto end; asfd->fdtype=ASFD_FD_SERVER_LISTEN_MAIN; // I think that this is probably the best point at which to run a // cleanup job to delete unused data files, because no other process // can fiddle with the dedup_group at this point. // Cannot do it on a resume, or it will delete files that are // referenced in the backup we are resuming. if(delete_unused_data_files(sdirs, resume)) goto end; // Load the sparse indexes for this dedup group. if(!(scores=champ_chooser_init(sdirs->data))) goto end; while(1) { for(asfd=as->asfd->next; asfd; asfd=asfd->next) { if(!asfd->blist->head || asfd->blist->head->got==BLK_INCOMING) continue; if(results_to_fd(asfd)) goto end; } int removed; switch(as->read_write(as)) { case 0: // Check the main socket last, as it might add // a new client to the list. for(asfd=as->asfd->next; asfd; asfd=asfd->next) { while(asfd->rbuf->buf) { if(deal_with_client_rbuf(asfd, directory, scores)) goto end; // Get as much out of the // readbuf as possible. if(asfd->parse_readbuf(asfd)) goto end; } } if(as->asfd->new_client) { // Incoming client. as->asfd->new_client=0; if(champ_chooser_new_client(as, confs)) goto end; started=1; } break; default: removed=0; // Maybe one of the fds had a problem. // Find and remove it and carry on if possible. for(asfd=as->asfd->next; asfd; ) { struct asfd *a; if(!asfd->want_to_remove) { asfd=asfd->next; continue; } as->asfd_remove(as, asfd); logp("%s: disconnected fd %d\n", asfd->desc, asfd->fd); a=asfd->next; asfd_free(&asfd); asfd=a; removed++; } if(removed) break; // If we got here, there was no fd to remove. // It is a fatal error. goto end; } if(started && !as->asfd->next) { logp("All clients disconnected.\n"); ret=0; break; } } end: logp("champ chooser exiting: %d\n", ret); champ_chooser_free(&scores); log_fzp_set(NULL, confs); async_free(&as); asfd_free(&asfd); // This closes s for us. close_fd(&s); unlink(sdirs->champsock); // FIX THIS: free asfds. lock_release(lock); lock_free(&lock); return ret; }
static int usb_host_handle_control(USBHostDevice *s, USBPacket *p) { struct usbdevfs_urb *urb; AsyncURB *aurb; int ret, value, index; /* * Process certain standard device requests. * These are infrequent and are processed synchronously. */ value = le16_to_cpu(s->ctrl.req.wValue); index = le16_to_cpu(s->ctrl.req.wIndex); dprintf("husb: ctrl type 0x%x req 0x%x val 0x%x index %u len %u\n", s->ctrl.req.bRequestType, s->ctrl.req.bRequest, value, index, s->ctrl.len); if (s->ctrl.req.bRequestType == 0) { switch (s->ctrl.req.bRequest) { case USB_REQ_SET_ADDRESS: return usb_host_set_address(s, value); case USB_REQ_SET_CONFIGURATION: return usb_host_set_config(s, value & 0xff); } } if (s->ctrl.req.bRequestType == 1 && s->ctrl.req.bRequest == USB_REQ_SET_INTERFACE) return usb_host_set_interface(s, index, value); /* The rest are asynchronous */ aurb = async_alloc(); if (!aurb) { dprintf("husb: async malloc failed\n"); return USB_RET_NAK; } aurb->hdev = s; aurb->packet = p; /* * Setup ctrl transfer. * * s->ctrl is layed out such that data buffer immediately follows * 'req' struct which is exactly what usbdevfs expects. */ urb = &aurb->urb; urb->type = USBDEVFS_URB_TYPE_CONTROL; urb->endpoint = p->devep; urb->buffer = &s->ctrl.req; urb->buffer_length = 8 + s->ctrl.len; urb->usercontext = s; ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb); dprintf("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb); if (ret < 0) { dprintf("husb: submit failed. errno %d\n", errno); async_free(aurb); switch(errno) { case ETIMEDOUT: return USB_RET_NAK; case EPIPE: default: return USB_RET_STALL; } } usb_defer_packet(p, async_cancel, aurb); return USB_RET_ASYNC; }
static int run_server(struct conf **confs, const char *conffile, int *rfds, int *sfds) { int i=0; int ret=-1; SSL_CTX *ctx=NULL; int found_normal_child=0; struct asfd *asfd=NULL; struct asfd *scfd=NULL; struct async *mainas=NULL; const char *port=get_string(confs[OPT_PORT]); const char *address=get_string(confs[OPT_ADDRESS]); const char *status_port=get_string(confs[OPT_STATUS_PORT]); const char *status_address=get_string(confs[OPT_STATUS_ADDRESS]); if(!(ctx=ssl_initialise_ctx(confs))) { logp("error initialising ssl ctx\n"); goto end; } if((ssl_load_dh_params(ctx, confs))) { logp("error loading dh params\n"); goto end; } if(init_listen_socket(address, port, rfds) || init_listen_socket(status_address, status_port, sfds)) goto end; if(!(mainas=async_alloc()) || mainas->init(mainas, 0)) goto end; for(i=0; i<LISTEN_SOCKETS && rfds[i]!=-1; i++) { struct asfd *newfd; if(!(newfd=setup_asfd(mainas, "main server socket", &rfds[i]))) goto end; newfd->fdtype=ASFD_FD_SERVER_LISTEN_MAIN; } for(i=0; i<LISTEN_SOCKETS && sfds[i]!=-1; i++) { struct asfd *newfd; if(!(newfd=setup_asfd(mainas, "main server status socket", &sfds[i]))) goto end; newfd->fdtype=ASFD_FD_SERVER_LISTEN_STATUS; } while(!hupreload) { switch(mainas->read_write(mainas)) { case 0: for(asfd=mainas->asfd; asfd; asfd=asfd->next) { if(asfd->new_client) { // Incoming client. asfd->new_client=0; if(process_incoming_client(asfd, ctx, conffile, confs)) goto end; if(!get_int(confs[OPT_FORK])) { gentleshutdown++; ret=1; goto end; } continue; } } break; default: int removed=0; // Maybe one of the fds had a problem. // Find and remove it and carry on if possible. for(asfd=mainas->asfd; asfd; ) { struct asfd *a; if(!asfd->want_to_remove) { asfd=asfd->next; continue; } mainas->asfd_remove(mainas, asfd); logp("%s: disconnected fd %d\n", asfd->desc, asfd->fd); a=asfd->next; asfd_free(&asfd); asfd=a; removed++; } if(removed) break; // If we got here, there was no fd to remove. // It is a fatal error. goto end; } for(asfd=mainas->asfd; asfd; asfd=asfd->next) { if(asfd->fdtype!=ASFD_FD_SERVER_PIPE_READ || !asfd->rbuf->buf) continue; // One of the child processes is giving us information. // Try to append it to any of the status child pipes. for(scfd=mainas->asfd; scfd; scfd=scfd->next) { if(scfd->fdtype!=ASFD_FD_SERVER_PIPE_WRITE) continue; switch(scfd->append_all_to_write_buffer(scfd, asfd->rbuf)) { case APPEND_OK: case APPEND_BLOCKED: break; default: goto end; } } // Free the information, even if we did not manage // to append it. That should be OK, more will be along // soon. iobuf_free_content(asfd->rbuf); } chld_check_for_exiting(mainas); // Leave if we had a SIGUSR1 and there are no children running. if(gentleshutdown) { if(!gentleshutdown_logged) { logp("got SIGUSR2 gentle reload signal\n"); logp("will shut down once children have exited\n"); gentleshutdown_logged++; } // FIX THIS: // found_normal_child=chld_add_fd_to_normal_sets(confs, &fsr, &fse, &mfd); else if(!found_normal_child) { logp("all children have exited - shutting down\n"); break; } } } if(hupreload) logp("got SIGHUP reload signal\n"); ret=0; end: async_asfd_free_all(&mainas); if(ctx) ssl_destroy_ctx(ctx); return ret; }
static int usb_host_handle_data(USBHostDevice *s, USBPacket *p) { struct usbdevfs_urb *urb; AsyncURB *aurb; int ret; aurb = async_alloc(); if (!aurb) { dprintf("husb: async malloc failed\n"); return USB_RET_NAK; } aurb->hdev = s; aurb->packet = p; urb = &aurb->urb; if (p->pid == USB_TOKEN_IN) urb->endpoint = p->devep | 0x80; else urb->endpoint = p->devep; if (is_halted(s, p->devep)) { ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &urb->endpoint); if (ret < 0) { dprintf("husb: failed to clear halt. ep 0x%x errno %d\n", urb->endpoint, errno); return USB_RET_NAK; } clear_halt(s, p->devep); } urb->buffer = p->data; urb->buffer_length = p->len; if (is_isoc(s, p->devep)) { /* Setup ISOC transfer */ urb->type = USBDEVFS_URB_TYPE_ISO; urb->flags = USBDEVFS_URB_ISO_ASAP; urb->number_of_packets = 1; urb->iso_frame_desc[0].length = p->len; } else { /* Setup bulk transfer */ urb->type = USBDEVFS_URB_TYPE_BULK; } urb->usercontext = s; ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb); dprintf("husb: data submit. ep 0x%x len %u aurb %p\n", urb->endpoint, p->len, aurb); if (ret < 0) { dprintf("husb: submit failed. errno %d\n", errno); async_free(aurb); switch(errno) { case ETIMEDOUT: return USB_RET_NAK; case EPIPE: default: return USB_RET_STALL; } } usb_defer_packet(p, async_cancel, aurb); return USB_RET_ASYNC; }
static int run_child(int *cfd, SSL_CTX *ctx, struct sockaddr_storage *addr, int status_wfd, int status_rfd, const char *conffile, int forking) { int ret=-1; int ca_ret=0; SSL *ssl=NULL; BIO *sbio=NULL; struct conf **confs=NULL; struct conf **cconfs=NULL; struct cntr *cntr=NULL; struct async *as=NULL; const char *cname=NULL; struct asfd *asfd=NULL; int is_status_server=0; if(!(confs=confs_alloc()) || !(cconfs=confs_alloc())) goto end; set_peer_env_vars(addr); // Reload global config, in case things have changed. This means that // the server does not need to be restarted for most conf changes. confs_init(confs); confs_init(cconfs); if(conf_load_global_only(conffile, confs)) goto end; // Hack to keep forking turned off if it was specified as off on the // command line. if(!forking) set_int(confs[OPT_FORK], 0); if(!(sbio=BIO_new_socket(*cfd, BIO_NOCLOSE)) || !(ssl=SSL_new(ctx))) { logp("There was a problem joining ssl to the socket\n"); goto end; } SSL_set_bio(ssl, sbio, sbio); /* Do not try to check peer certificate straight away. Clients can send a certificate signing request when they have no certificate. */ SSL_set_verify(ssl, SSL_VERIFY_PEER /* | SSL_VERIFY_FAIL_IF_NO_PEER_CERT */, 0); if(ssl_do_accept(ssl)) goto end; if(!(as=async_alloc()) || as->init(as, 0) || !(asfd=setup_asfd_ssl(as, "main socket", cfd, ssl))) goto end; asfd->set_timeout(asfd, get_int(confs[OPT_NETWORK_TIMEOUT])); asfd->ratelimit=get_float(confs[OPT_RATELIMIT]); if(authorise_server(as->asfd, confs, cconfs) || !(cname=get_string(cconfs[OPT_CNAME])) || !*cname) { // Add an annoying delay in case they are tempted to // try repeatedly. log_and_send(as->asfd, "unable to authorise on server"); sleep(1); goto end; } if(!get_int(cconfs[OPT_ENABLED])) { log_and_send(as->asfd, "client not enabled on server"); sleep(1); goto end; } // Set up counters. Have to wait until here to get cname. if(!(cntr=cntr_alloc()) || cntr_init(cntr, cname)) goto end; set_cntr(confs[OPT_CNTR], cntr); set_cntr(cconfs[OPT_CNTR], cntr); /* At this point, the client might want to get a new certificate signed. Clients on 1.3.2 or newer can do this. */ if((ca_ret=ca_server_maybe_sign_client_cert(as->asfd, confs, cconfs))<0) { logp("Error signing client certificate request for %s\n", cname); goto end; } else if(ca_ret>0) { // Certificate signed and sent back. // Everything is OK, but we will close this instance // so that the client can start again with a new // connection and its new certificates. logp("Signed and returned client certificate request for %s\n", cname); ret=0; goto end; } /* Now it is time to check the certificate. */ if(ssl_check_cert(ssl, confs, cconfs)) { log_and_send(as->asfd, "check cert failed on server"); goto end; } if(status_rfd>=0) { is_status_server=1; if(!setup_asfd(as, "status server parent socket", &status_rfd)) goto end; } ret=child(as, is_status_server, status_wfd, confs, cconfs); end: *cfd=-1; if(as && asfd_flush_asio(as->asfd)) ret=-1; async_asfd_free_all(&as); // This closes cfd for us. logp("exit child\n"); if(cntr) cntr_free(&cntr); if(confs) { set_cntr(confs[OPT_CNTR], NULL); confs_free(&confs); } if(cconfs) { set_cntr(cconfs[OPT_CNTR], NULL); confs_free(&cconfs); } return ret; }
int status_client_ncurses(enum action act, struct conf **confs) { int csin=-1; int csout=-1; int ret=-1; pid_t childpid=-1; struct async *as=NULL; const char *monitor_logfile=get_string(confs[OPT_MONITOR_LOGFILE]); #ifdef HAVE_NCURSES_H actg=act; // So that the sighandler can call endwin(). #else if(act==ACTION_STATUS) { printf("To use the live status monitor, you need to recompile with ncurses support.\n"); goto end; } #endif setup_signals(); // Fork a burp child process that will contact the server over SSL. // We will read and write from and to its stdout and stdin. if((childpid=fork_monitor(&csin, &csout, confs))<0) goto end; //printf("childpid: %d\n", childpid); set_non_blocking(csin); set_non_blocking(csout); if(!(as=async_alloc()) || as->init(as, 0) || !setup_asfd(as, "monitor stdin", &csin, NULL, ASFD_STREAM_LINEBUF, ASFD_FD_CLIENT_MONITOR_WRITE, -1, confs) || !setup_asfd(as, "monitor stdout", &csout, NULL, ASFD_STREAM_LINEBUF, ASFD_FD_CLIENT_MONITOR_READ, -1, confs)) goto end; //printf("ml: %s\n", monitor_logfile); #ifdef HAVE_NCURSES_H if(actg==ACTION_STATUS) { int stdinfd=fileno(stdin); if(!setup_asfd(as, "stdin", &stdinfd, NULL, ASFD_STREAM_NCURSES_STDIN, ASFD_FD_CLIENT_NCURSES_READ, -1, confs)) goto end; ncurses_init(); } #endif if(monitor_logfile && !(lfp=open_file(monitor_logfile, "wb"))) goto end; set_logfp_direct(lfp); ret=main_loop(as, act, confs); end: #ifdef HAVE_NCURSES_H if(actg==ACTION_STATUS) endwin(); #endif if(ret) logp("%s exiting with error: %d\n", __func__, ret); close_fp(&lfp); async_asfd_free_all(&as); close_fd(&csin); close_fd(&csout); return ret; }
static enum cliret do_client(struct conf *conf, enum action action, int vss_restore, int json) { enum cliret ret=CLIENT_OK; int rfd=-1; int resume=0; SSL *ssl=NULL; SSL_CTX *ctx=NULL; struct cntr *cntr=NULL; char *incexc=NULL; long name_max=0; enum action act=action; struct async *as=NULL; struct asfd *asfd=NULL; // as->settimers(0, 100); logp("begin client\n"); if(!(cntr=cntr_alloc()) || cntr_init(cntr, conf->cname)) goto error; conf->cntr=cntr; if(act!=ACTION_ESTIMATE && ssl_setup(&rfd, &ssl, &ctx, conf)) goto error; if(!(as=async_alloc()) || !(asfd=asfd_alloc()) || as->init(as, act==ACTION_ESTIMATE) || asfd->init(asfd, as, rfd, ssl, conf)) goto end; as->add_asfd(as, asfd); // Set quality of service bits on backup packets. if(act==ACTION_BACKUP || act==ACTION_BACKUP_TIMED || act==ACTION_TIMER_CHECK) as->asfd->set_bulk_packets(as->asfd); if(act!=ACTION_ESTIMATE) { if((ret=initial_comms(as, &act, &incexc, &name_max, conf))) goto end; } rfd=-1; switch(act) { case ACTION_BACKUP: ret=backup_wrapper(asfd, act, "backupphase1", incexc, resume, name_max, conf); break; case ACTION_BACKUP_TIMED: ret=backup_wrapper(asfd, act, "backupphase1timed", incexc, resume, name_max, conf); break; case ACTION_TIMER_CHECK: ret=backup_wrapper(asfd, act, "backupphase1timedcheck", incexc, resume, name_max, conf); break; case ACTION_RESTORE: case ACTION_VERIFY: ret=restore_wrapper(asfd, act, vss_restore, conf); break; case ACTION_ESTIMATE: if(do_backup_client(asfd, conf, act, name_max, 0)) goto error; break; case ACTION_DELETE: if(do_delete_client(asfd, conf)) goto error; break; case ACTION_LIST: case ACTION_LONG_LIST: default: if(do_list_client(asfd, conf, act, json)) goto error; break; } goto end; error: ret=CLIENT_ERROR; end: close_fd(&rfd); async_free(&as); asfd_free(&asfd); if(ctx) ssl_destroy_ctx(ctx); if(incexc) free(incexc); conf->cntr=NULL; if(cntr) cntr_free(&cntr); //logp("end client\n"); return ret; }
static enum cliret do_client(struct conf **confs, enum action action, int vss_restore) { enum cliret ret=CLIENT_OK; int rfd=-1; SSL *ssl=NULL; SSL_CTX *ctx=NULL; struct cntr *cntr=NULL; char *incexc=NULL; enum action act=action; struct async *as=NULL; struct asfd *asfd=NULL; // as->settimers(0, 100); // logp("begin client\n"); // logp("action %d\n", action); // Status monitor forks a child process instead of connecting to // the server directly. if(action==ACTION_STATUS || action==ACTION_STATUS_SNAPSHOT) { #ifdef HAVE_WIN32 logp("Status mode not implemented on Windows.\n"); goto error; #endif if(status_client_ncurses_init(act) || status_client_ncurses(confs)) ret=CLIENT_ERROR; goto end; } if(!(cntr=cntr_alloc()) || cntr_init(cntr, get_string(confs[OPT_CNAME]))) goto error; set_cntr(confs[OPT_CNTR], cntr); if(act!=ACTION_ESTIMATE && ssl_setup(&rfd, &ssl, &ctx, action, confs)) goto could_not_connect; if(!(as=async_alloc()) || !(asfd=asfd_alloc()) || as->init(as, act==ACTION_ESTIMATE) || asfd->init(asfd, "main socket", as, rfd, ssl, ASFD_STREAM_STANDARD, confs)) goto end; as->asfd_add(as, asfd); // Set quality of service bits on backup packets. if(act==ACTION_BACKUP || act==ACTION_BACKUP_TIMED || act==ACTION_TIMER_CHECK) as->asfd->set_bulk_packets(as->asfd); if(act!=ACTION_ESTIMATE) { if((ret=initial_comms(as, &act, &incexc, confs))) goto end; } rfd=-1; switch(act) { case ACTION_BACKUP: ret=backup_wrapper(asfd, act, "backupphase1", incexc, confs); break; case ACTION_BACKUP_TIMED: ret=backup_wrapper(asfd, act, "backupphase1timed", incexc, confs); break; case ACTION_TIMER_CHECK: ret=backup_wrapper(asfd, act, "backupphase1timedcheck", incexc, confs); break; case ACTION_RESTORE: case ACTION_VERIFY: ret=restore_wrapper(asfd, act, vss_restore, confs); break; case ACTION_ESTIMATE: if(do_backup_client(asfd, confs, act, 0)) goto error; break; case ACTION_DELETE: if(do_delete_client(asfd, confs)) goto error; break; case ACTION_MONITOR: if(do_monitor_client(asfd, confs)) goto error; break; case ACTION_DIFF: case ACTION_DIFF_LONG: /* if(!strcmp(get_string(confs[OPT_BACKUP2]), "n")) // Do a phase1 scan and diff that. ret=backup_wrapper(asfd, act, "backupphase1diff", incexc, confs); else */ // Diff two backups that already exist. // Fall through, the list code is all we need // for simple diffs on the client side. case ACTION_LIST: case ACTION_LIST_LONG: default: if(do_list_client(asfd, act, confs)) goto error; break; } if(asfd_flush_asio(asfd)) ret=CLIENT_ERROR; goto end; error: ret=CLIENT_ERROR; goto end; could_not_connect: ret=CLIENT_COULD_NOT_CONNECT; end: close_fd(&rfd); async_free(&as); asfd_free(&asfd); if(ctx) ssl_destroy_ctx(ctx); free_w(&incexc); set_cntr(confs[OPT_CNTR], NULL); cntr_free(&cntr); //logp("end client\n"); return ret; }
static int run_child(int *rfd, int *cfd, SSL_CTX *ctx, const char *conffile, int forking) { int ret=-1; int ca_ret=0; SSL *ssl=NULL; BIO *sbio=NULL; struct conf *conf=NULL; struct conf *cconf=NULL; struct cntr *cntr=NULL; struct async *as=NULL; struct asfd *asfd=NULL; if(!(conf=conf_alloc()) || !(cconf=conf_alloc())) goto end; if(forking) close_fd(rfd); // Reload global config, in case things have changed. This means that // the server does not need to be restarted for most conf changes. conf_init(conf); conf_init(cconf); if(conf_load(conffile, conf, 1)) goto end; // Hack to keep forking turned off if it was specified as off on the // command line. if(!forking) conf->forking=0; if(!(sbio=BIO_new_socket(*cfd, BIO_NOCLOSE)) || !(ssl=SSL_new(ctx))) { logp("There was a problem joining ssl to the socket\n"); goto end; } SSL_set_bio(ssl, sbio, sbio); /* Do not try to check peer certificate straight away. Clients can send a certificate signing request when they have no certificate. */ SSL_set_verify(ssl, SSL_VERIFY_PEER /* | SSL_VERIFY_FAIL_IF_NO_PEER_CERT */, 0); if(SSL_accept(ssl)<=0) { char buf[256]=""; ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); logp("SSL_accept: %s\n", buf); goto end; } if(!(as=async_alloc()) || !(asfd=asfd_alloc()) || as->init(as, 0) || asfd->init(asfd, "main socket", as, *cfd, ssl, conf)) goto end; as->asfd_add(as, asfd); if(authorise_server(asfd, conf, cconf) || !cconf->cname || !*(cconf->cname)) { // Add an annoying delay in case they are tempted to // try repeatedly. log_and_send(asfd, "unable to authorise on server"); sleep(1); goto end; } // Set up counters. Have to wait until here to get cname. if(!(cntr=cntr_alloc()) || cntr_init(cntr, cconf->cname)) goto end; conf->cntr=cntr; cconf->cntr=cntr; /* At this point, the client might want to get a new certificate signed. Clients on 1.3.2 or newer can do this. */ if((ca_ret=ca_server_maybe_sign_client_cert(asfd, conf, cconf))<0) { logp("Error signing client certificate request for %s\n", cconf->cname); goto end; } else if(ca_ret>0) { // Certificate signed and sent back. // Everything is OK, but we will close this instance // so that the client can start again with a new // connection and its new certificates. logp("Signed and returned client certificate request for %s\n", cconf->cname); ret=0; goto end; } /* Now it is time to check the certificate. */ if(ssl_check_cert(ssl, cconf)) { log_and_send(asfd, "check cert failed on server"); goto end; } set_non_blocking(*cfd); ret=child(as, conf, cconf); end: *cfd=-1; async_free(&as); asfd_free(&asfd); // This closes cfd for us. logp("exit child\n"); if(cntr) cntr_free(&cntr); if(conf) conf_free(conf); if(cconf) conf_free(cconf); return ret; }