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