1 #include "../../../burp.h"
2 #include "../../../alloc.h"
3 #include "../../../asfd.h"
4 #include "../../../async.h"
5 #include "../../../cmd.h"
6 #include "../../../conf.h"
7 #include "../../../fsops.h"
8 #include "../../../lock.h"
9 #include "../../../log.h"
10 #include "../../../prepend.h"
11 #include "champ_client.h"
12 #include "champ_chooser.h"
13 #include "champ_server.h"
14
15 #include <sys/un.h>
16
champ_chooser_fork(struct sdirs * sdirs,struct conf ** confs,int resume)17 static int champ_chooser_fork(struct sdirs *sdirs, struct conf **confs,
18 int resume)
19 {
20 pid_t childpid=-1;
21 int cret;
22
23 if(!get_int(confs[OPT_FORK]))
24 {
25 logp("Not forking a champ chooser process.\n");
26 // They need to manually run a separate process.
27 return 0;
28 }
29
30 switch((childpid=fork()))
31 {
32 case -1:
33 logp("fork failed in %s: %s\n",
34 __func__, strerror(errno));
35 return -1;
36 case 0:
37 // Child.
38 log_fzp_set(NULL, confs);
39 switch(champ_chooser_server(sdirs, confs, resume))
40 {
41 case 0:
42 cret=0;
43 break;
44 default:
45 cret=1;
46 break;
47 }
48 exit(cret);
49 default:
50 // Parent.
51 logp("forked champ chooser pid %d\n", childpid);
52 return 0;
53 }
54 return -1; // Not reached.
55 }
56
connect_to_champ_chooser(struct sdirs * sdirs,struct conf ** confs,int resume)57 static int connect_to_champ_chooser(struct sdirs *sdirs, struct conf **confs,
58 int resume)
59 {
60 int len;
61 int s=-1;
62 int tries=0;
63 int tries_max=3;
64 struct sockaddr_un remote;
65
66 if(!lock_test(sdirs->champlock))
67 {
68 // Champ chooser is not running.
69 // Try to fork a new champ chooser process.
70 if(champ_chooser_fork(sdirs, confs, resume))
71 return -1;
72 }
73
74 // Champ chooser should either be running now, or about to run.
75
76 if((s=socket(AF_UNIX, SOCK_STREAM, 0))<0)
77 {
78 logp("socket error in %s: %s\n", __func__, strerror(errno));
79 return -1;
80 }
81
82 memset(&remote, 0, sizeof(struct sockaddr_un));
83 remote.sun_family=AF_UNIX;
84 snprintf(remote.sun_path, sizeof(remote.sun_path),
85 "%s", sdirs->champsock);
86 len=strlen(remote.sun_path)+sizeof(remote.sun_family)+1;
87
88 while(tries++<tries_max)
89 {
90 int sleeptimeleft=3;
91 if(!connect(s, (struct sockaddr *)&remote, len))
92 {
93 logp("Connected to champ chooser.\n");
94 return s;
95 }
96
97 // SIGCHLDs may be interrupting.
98 sleeptimeleft=3;
99 while(sleeptimeleft>0) sleeptimeleft=sleep(sleeptimeleft);
100 }
101
102 // Only log any error after all attempts failed, to make the logs
103 // less worrying (most of the time, the first attempt will fail).
104 logp("Could not connect to champ chooser on %s after %d attempts: %s\n",
105 sdirs->champsock, tries_max, strerror(errno));
106
107 return -1;
108 }
109
champ_chooser_connect(struct async * as,struct sdirs * sdirs,struct conf ** confs,int resume)110 struct asfd *champ_chooser_connect(struct async *as,
111 struct sdirs *sdirs, struct conf **confs, int resume)
112 {
113 int champsock=-1;
114 char *champname=NULL;
115 struct asfd *chfd=NULL;
116 const char *cname=NULL;
117
118 // Connect to champ chooser now.
119 // This may start up a new champ chooser. On a machine with multiple
120 // cores, it may be faster to do now, way before it is actually needed
121 // in phase2.
122 if((champsock=connect_to_champ_chooser(sdirs, confs, resume))<0)
123 {
124 logp("could not connect to champ chooser\n");
125 goto error;
126 }
127
128 if(!(chfd=setup_asfd(as, "champ chooser socket", &champsock,
129 /*listen*/"")))
130 goto error;
131
132 cname=get_string(confs[OPT_CNAME]);
133 if(!(champname=prepend_n("cname", cname, strlen(cname), ":")))
134 goto error;
135
136 if(chfd->write_str(chfd, CMD_GEN, champname)
137 || asfd_read_expect(chfd, CMD_GEN, "cname ok"))
138 goto error;
139
140 free_w(&champname);
141 return chfd;
142 error:
143 free_w(&champname);
144 as->asfd_remove(as, chfd);
145 asfd_free(&chfd);
146 close_fd(&champsock);
147 return NULL;
148 }
149