1 /*
2  *   LASH
3  *
4  *   Copyright (C) 2002, 2003 Robert Ham <rah@bash.sh>
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include <stdint.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <errno.h>
29 #include <netdb.h>
30 #include <netinet/in.h> /* for ntohl() */
31 extern int h_errno;
32 
33 #include <lash/lash.h>
34 #include <lash/internal_headers.h>
35 
36 int
lash_comm_send_event(int socket,lash_comm_event_t * event)37 lash_comm_send_event(int socket, lash_comm_event_t * event)
38 {
39 	int err;
40 	size_t buf_size;
41 	char *buf;
42 
43 	switch (event->type) {
44 	case LASH_Comm_Event_Connect:
45 		lash_buffer_from_comm_event_connect(&buf, &buf_size,
46 											event->event_data.connect);
47 		break;
48 	case LASH_Comm_Event_Event:
49 		lash_buffer_from_comm_event_event(&buf, &buf_size,
50 										  event->event_data.event);
51 		break;
52 	case LASH_Comm_Event_Config:
53 		lash_buffer_from_comm_event_config(&buf, &buf_size,
54 										   event->event_data.config);
55 		break;
56 	case LASH_Comm_Event_Protocol_Mismatch:
57 		lash_buffer_from_comm_event_protocol_mismatch(&buf, &buf_size,
58 													  event->event_data.
59 													  number);
60 		break;
61 	case LASH_Comm_Event_Exec:
62 		lash_buffer_from_comm_event_exec(&buf, &buf_size,
63 										 event->event_data.exec);
64 		break;
65 	case LASH_Comm_Event_Close:
66 	case LASH_Comm_Event_Ping:
67 	case LASH_Comm_Event_Pong:
68 		lash_buffer_from_comm_event(&buf, &buf_size, event);
69 		break;
70 	default:
71 		break;
72 	}
73 
74 	/* send the buffer */
75 	err = lash_sendall(socket, buf, buf_size, 0);
76 	if (err == -1) {
77 		fprintf(stderr, "%s: error sending client event\n", __FUNCTION__);
78 	}
79 
80 	free(buf);
81 
82 	return err;
83 }
84 
85 int
lash_comm_recv_event(int socket,lash_comm_event_t * event)86 lash_comm_recv_event(int socket, lash_comm_event_t * event)
87 {
88 	char *buf;
89 	size_t buf_size;
90 	int err;
91 	uint32_t *iptr;
92 
93 	err = lash_recvall(socket, (void **)&buf, &buf_size, 0);
94 	if (err < 0)
95 		return err;
96 
97 	iptr = (uint32_t *) buf;
98 	event->type = ntohl(*iptr);
99 
100 	switch (event->type) {
101 	case LASH_Comm_Event_Connect:
102 		err = lash_comm_event_from_buffer_connect(buf, buf_size, event);
103 		if (err)
104 			return -3;
105 		break;
106 	case LASH_Comm_Event_Event:
107 		lash_comm_event_from_buffer_event(buf, buf_size, event);
108 		break;
109 	case LASH_Comm_Event_Config:
110 		lash_comm_event_from_buffer_config(buf, buf_size, event);
111 		break;
112 	case LASH_Comm_Event_Protocol_Mismatch:
113 		lash_comm_event_from_buffer_protocol_mismatch(buf, buf_size, event);
114 		break;
115 	case LASH_Comm_Event_Exec:
116 		lash_comm_event_from_buffer_exec(buf, buf_size, event);
117 		break;
118 	case LASH_Comm_Event_Close:
119 	case LASH_Comm_Event_Ping:
120 	case LASH_Comm_Event_Pong:
121 		lash_comm_event_from_buffer(buf, buf_size, event);
122 		break;
123 	default:
124 		break;
125 	}
126 
127 	free(buf);
128 
129 	return buf_size;
130 }
131 
132 int
lash_comm_connect_to_server(lash_client_t * client,const char * server,const char * service,lash_connect_params_t * connect)133 lash_comm_connect_to_server(lash_client_t * client, const char *server,
134 							const char *service,
135 							lash_connect_params_t * connect)
136 {
137 	lash_comm_event_t connect_event;
138 	int err;
139 
140 	err = lash_open_socket(&client->socket, server, service);
141 	if (err) {
142 		fprintf(stderr, "%s: could not create server connection\n",
143 				__FUNCTION__);
144 		return 1;
145 	}
146 
147 	connect_event.type = LASH_Comm_Event_Connect;
148 	connect_event.event_data.connect = connect;
149 
150 	LASH_PRINT_DEBUG("sending Connect event");
151 	err = lash_comm_send_event(client->socket, &connect_event);
152 	if (err == -1) {
153 		fprintf(stderr, "%s: error sending connect event to the server\n",
154 				__FUNCTION__);
155 		close(client->socket);
156 		return 1;
157 	}
158 	LASH_PRINT_DEBUG("Connect event sent");
159 
160 	return 0;
161 }
162 
163 static void
lash_comm_recv_finish(lash_client_t * client)164 lash_comm_recv_finish(lash_client_t * client)
165 {
166 	lash_list_t *node;
167 
168 	client->recv_close = 1;
169 	client->send_close = 1;
170 	pthread_cond_signal(&client->send_conditional);
171 	pthread_join(client->send_thread, NULL);
172 
173 	close(client->socket);
174 	/*lash_args_destroy(client->args);*/
175 	client->args = NULL;
176 	free(client->class);
177 	client->class = NULL;
178 
179 	pthread_mutex_destroy(&client->comm_events_out_lock);
180 	pthread_cond_destroy(&client->send_conditional);
181 
182 	for (node = client->comm_events_out; node; node = lash_list_next(node))
183 		lash_comm_event_destroy((lash_comm_event_t *) node->data);
184 	lash_list_free(client->comm_events_out);
185 }
186 
187 static void
lash_comm_recv_lost_server(lash_client_t * client)188 lash_comm_recv_lost_server(lash_client_t * client)
189 {
190 	lash_event_t *ev;
191 
192 	ev = lash_event_new_with_type(LASH_Server_Lost);
193 	pthread_mutex_lock(&client->events_in_lock);
194 	client->events_in = lash_list_append(client->events_in, ev);
195 	pthread_mutex_unlock(&client->events_in_lock);
196 
197 	client->server_connected = 0;
198 	lash_comm_recv_finish(client);
199 }
200 
201 void *
lash_comm_recv_run(void * data)202 lash_comm_recv_run(void *data)
203 {
204 	lash_client_t *client;
205 	lash_comm_event_t comm_event;
206 	lash_event_t *event;
207 	lash_config_t *config;
208 	int err;
209 
210 	client = (lash_client_t *) data;
211 
212 	while (!client->recv_close) {
213 		err = lash_comm_recv_event(client->socket, &comm_event);
214 
215 		if (err == -1) {
216 			fprintf(stderr, "%s: error recieving event\n", __FUNCTION__);
217 			continue;
218 		}
219 
220 		if (err == -2) {
221 			LASH_PRINT_DEBUG("server disconnected");
222 			lash_comm_recv_lost_server(client);
223 		}
224 
225 		switch (comm_event.type) {
226 		case LASH_Comm_Event_Event:
227 			event = comm_event.event_data.event;
228 
229 			/* add the event to the event buffer */
230 			pthread_mutex_lock(&client->events_in_lock);
231 			client->events_in = lash_list_append(client->events_in, event);
232 			pthread_mutex_unlock(&client->events_in_lock);
233 
234 			break;
235 
236 		case LASH_Comm_Event_Config:
237 			config = comm_event.event_data.config;
238 
239 			LASH_DEBUGARGS("recieved config with key '%s'",
240 						   lash_config_get_key(config));
241 
242 			/* add to the configs */
243 			pthread_mutex_lock(&client->configs_in_lock);
244 			client->configs_in = lash_list_append(client->configs_in, config);
245 			pthread_mutex_unlock(&client->configs_in_lock);
246 
247 			break;
248 
249 		case LASH_Comm_Event_Ping:{
250 			lash_comm_event_t *ev;
251 
252 			ev = lash_comm_event_new();
253 			lash_comm_event_set_type(ev, LASH_Comm_Event_Pong);
254 
255 			pthread_mutex_lock(&client->comm_events_out_lock);
256 			client->comm_events_out =
257 				lash_list_append(client->comm_events_out, ev);
258 			pthread_mutex_unlock(&client->comm_events_out_lock);
259 			pthread_cond_signal(&client->send_conditional);
260 			break;
261 		}
262 
263 		case LASH_Comm_Event_Protocol_Mismatch:
264 			fprintf(stderr,
265 					"%s: protocol version mismatch!; server is using protocol version %s\n",
266 					__FUNCTION__,
267 					lash_protocol_string(comm_event.event_data.number));
268 			lash_comm_recv_lost_server(client);
269 			break;
270 
271 		case LASH_Comm_Event_Close:
272 			lash_comm_recv_finish(client);
273 			break;
274 
275 		default:
276 			fprintf(stderr, "%s: recieved unknown event of type %d\n",
277 					__FUNCTION__, comm_event.type);
278 			break;
279 		}
280 	}
281 
282 	return NULL;
283 }
284 
285 void *
lash_comm_send_run(void * data)286 lash_comm_send_run(void *data)
287 {
288 	lash_client_t *client;
289 	lash_list_t *list;
290 	lash_comm_event_t *comm_event;
291 	int err;
292 
293 	client = (lash_client_t *) data;
294 
295 	while (!client->send_close) {
296 		pthread_mutex_lock(&client->comm_events_out_lock);
297 		list = client->comm_events_out;
298 		if (list) {
299 			client->comm_events_out = NULL;
300 		} else {
301 			pthread_cond_wait(&client->send_conditional,
302 							  &client->comm_events_out_lock);
303 			list = client->comm_events_out;
304 			client->comm_events_out = NULL;
305 		}
306 		pthread_mutex_unlock(&client->comm_events_out_lock);
307 
308 		if (client->send_close)
309 			break;
310 
311 		while (list) {
312 			comm_event = (lash_comm_event_t *) list->data;
313 
314 			err = lash_comm_send_event(client->socket, comm_event);
315 			if (err == -1) {
316 				fprintf(stderr, "%s: error sending client comm event\n",
317 						__FUNCTION__);
318 			}
319 
320 			list = lash_list_remove(list, comm_event);
321 
322 			lash_comm_event_free(comm_event);
323 			free(comm_event);
324 		}
325 
326 	}
327 
328 	return NULL;
329 }
330 
331 /* EOF */
332