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