1/*
2**	BPALogin - lightweight portable BIDS2 login client
3**	Copyright (c) 2001-3 Shane Hyde, and others.
4**
5**  This program is free software; you can redistribute it and/or modify
6**  it under the terms of the GNU General Public License as published by
7**  the Free Software Foundation; either version 2 of the License, or
8**  (at your option) any later version.
9**
10**  This program is distributed in the hope that it will be useful,
11**  but WITHOUT ANY WARRANTY; without even the implied warranty of
12**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13**  GNU General Public License for more details.
14**
15**  You should have received a copy of the GNU General Public License
16**  along with this program; if not, write to the Free Software
17**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18**
19*/
20
21#include "bpalogin.h"
22
23void add_trans_data(struct transaction * t,char *p,int count)
24{
25	memcpy(t->data+t->length,p,count);
26	t->length += count;
27}
28
29void add_int2field(struct transaction * t,INT2 v)
30{
31	add_trans_data(t,(char *)&v,2);
32}
33
34void add_int4field(struct transaction * t,INT4 v)
35{
36	add_trans_data(t,(char *)&v,4);
37}
38
39void add_string(struct transaction * t,char *s)
40{
41	add_int2field(t,htons((INT2)(strlen(s)+4)));
42	add_trans_data(t,s,strlen(s));
43}
44
45void add_data(struct transaction * t,char *s,int c)
46{
47	add_int2field(t,htons((INT2)(c+4)));
48	add_trans_data(t,s,c);
49}
50
51void add_field_string(struct session *s,struct transaction * t,INT2 fn,char * p)
52{
53	s->debug(2,"Sending parm %d value %s\n",fn,p);
54
55	add_int2field(t,htons(fn));
56	add_string(t,p);
57}
58
59void add_field_data(struct session *s,struct transaction * t,INT2 fn,char * p,int c)
60{
61	s->debug(2,"Sending parm %d value %s\n",fn,p);
62
63	add_int2field(t,htons(fn));
64	add_data(t,p,c);
65}
66
67void add_field_INT2(struct session *s,struct transaction * t,INT2 fn,INT2 v)
68{
69	s->debug(2,"Sending parm %d value %d\n",fn,v);
70
71	add_int2field(t,htons(fn));
72	add_int2field(t,htons(6));
73	add_int2field(t,htons(v));
74}
75
76void add_field_INT4(struct session *s,struct transaction * t,INT2 fn,INT4 v)
77{
78	s->debug(2,"Sending parm %d value %d\n",fn,v);
79
80	add_int2field(t,htons(fn));
81	add_int2field(t,htons(8));
82	add_int4field(t,htonl(v));
83}
84
85void start_transaction(struct transaction * t,INT2 msgtype,INT4 sessionid)
86{
87	t->length = 0;
88	memset(t->data,0,1512);
89	add_int2field(t,htons(msgtype));
90	add_int2field(t,htons(0));
91	add_int4field(t,htonl(sessionid));
92}
93
94void dump_transaction(struct session * s,struct transaction * t)
95{
96	int i;
97	char * p = t->data;
98	i = 0;
99	while(i < t->length)
100	{
101		s->debug(3,"%d:%02x ",i,(unsigned char)*(p));
102
103		p++;
104		i++;
105	}
106	s->debug(3,"\n");
107
108}
109
110void dump_sent_transaction(struct session *s,struct transaction * t)
111{
112	s->debug(3,"Sent transaction:\n");
113	dump_transaction(s,t);
114}
115
116void dump_recv_transaction(struct session *s,struct transaction * t)
117{
118	s->debug(3,"Received transaction:\n");
119	dump_transaction(s,t);
120}
121
122void send_transaction(struct session *s,int socket,struct transaction * t)
123{
124	int r;
125	INT2 * lll;
126
127	lll = (INT2 *)(t->data+2);
128	*lll = htons((INT2)t->length);
129
130	r = send(socket,(void *)t,t->length,0);
131	dump_sent_transaction(s,t);
132}
133
134void send_udp_transaction(struct session * s,struct transaction * t)
135{
136	int r;
137
138	INT2 * lll;
139
140	lll = (INT2 *)(t->data+2);
141	*lll = htons((INT2)t->length);
142
143	s->fromaddr.sin_port = htons(s->statusport);
144	r = sendto(s->listensock,(void *)t,t->length,0,(struct sockaddr *)&s->fromaddr,sizeof(s->fromaddr));
145	dump_sent_transaction(s,t);
146}
147
148INT2 receive_transaction(struct session *s,int socket,struct transaction * t)
149{
150	INT2 * v;
151	int r = recv(socket,(char *)t,1500,0);
152
153	t->length = r;
154	dump_recv_transaction(s,t);
155
156	v = (INT2 *)t;
157
158	return r>0?ntohs(*v):0;
159}
160
161int check_hb_packet(struct session * s,struct transaction * t,int length)
162{
163	INT2 type;
164
165	type = ntohs(*(INT2 *)t);
166	if(type != T_MSG_STATUS_REQ)
167	{
168		s->debug(0,"Incorrect transaction type %d",type);
169		return 0;
170	}
171
172	if(length != 8)
173	{
174		s->debug(0,"Incorrect transaction length %d",length);
175		return 0;
176	}
177	return 1;
178}
179
180INT2 receive_udp_transaction(struct session *s,int socket,struct transaction * t,struct sockaddr_in *addr)
181{
182	struct timeval timeval;
183	fd_set readfds;
184	INT2 * v;
185	int l = sizeof(struct sockaddr_in);
186	int r,i;
187
188	timeval.tv_sec = s->maxheartbeat;
189	timeval.tv_usec = 0;
190	FD_ZERO(&readfds);
191	FD_SET(socket,&readfds);
192
193	r = select(socket+1,&readfds,NULL,NULL,&timeval);
194
195	if(r == -1)
196	{
197		return (INT2) 0xfffe;
198	}
199	else if(!r)
200	{
201		return (INT2) 0xffff;
202	}
203	else
204	{
205		r = recvfrom(socket,(char *)t,1500,0,(struct sockaddr*)addr,&l);
206		if(r==-1)
207			return (INT2) 0xfffe;
208
209		if(s->lastheartbeat + s->minheartbeat > time(NULL))
210		{
211        		s->recenthb++;
212        		if(s->recenthb > 3)
213        		{
214        			s->debug(0,"Heartbeats arriving too quickly - discarding\n");
215				return (INT2)0xfffd;
216
217        		}
218		}
219		else
220        		s->recenthb = 0;
221
222		s->lastheartbeat = time(NULL);
223	}
224
225	for(i = 0;i<s->tsmcount;i++)
226	{
227		if(addr->sin_addr.s_addr == s->tsmlist_in[i].sin_addr.s_addr)
228			break;
229	}
230	if(i == s->tsmcount)
231	{
232		s->debug(0,"Received a heartbeat from unexpected source %s:%d\n",inet_ntoa(addr->sin_addr),ntohs(addr->sin_port));
233		return (INT2)0xfffd;
234	}
235
236	t->length = r;
237
238	dump_recv_transaction(s,t);
239	/*
240	**  Lets make sure this packet is structured correctly
241	*/
242	if(!check_hb_packet(s,t,r))
243	{
244		return (INT2)0xfffd;
245	}
246
247	dump_recv_transaction(s,t);
248
249	v = (INT2 *)t;
250
251	return r>0?ntohs(*v):0;
252}
253
254char * locate_parm(struct transaction * t,INT2 parm)
255{
256	char * p = t->data,*pp,*lp,*vp;
257	INT2 p1;
258	INT2 l;
259	int i;
260
261	i = 8;
262	p += 8;
263	while(i < t->length)
264	{
265		pp = p;
266		lp = p+2;
267		vp = p+4;
268
269		l = read_INT2(lp);
270		p1 = read_INT2(pp);
271
272		if(parm == p1)
273		{
274			return vp;
275		}
276		p += l;
277		i += l;
278	}
279	return NULL;
280}
281
282int extract_valueINT2(struct session *s,struct transaction * t,INT2 parm,INT2 *v)
283{
284	INT2 * pp = (INT2 *)locate_parm(t,parm);
285	if(pp)
286	{
287		*v = read_INT2(pp);
288		s->debug(2,"Received parm %d value %d\n",parm,*v);
289
290		return TRUE;
291	}
292	return FALSE;
293}
294
295int extract_valueINT4(struct session *s,struct transaction * t,INT2 parm,INT4 *v)
296{
297	INT4 * pp = (INT4 *)locate_parm(t,parm);
298	if(pp)
299	{
300		*v = read_INT4(pp);
301		s->debug(2,"Received parm %d value %d\n",parm,*v);
302
303		return TRUE;
304	}
305	return FALSE;
306}
307
308int extract_valuestring(struct session *s,struct transaction * t,INT2 parm,char * v)
309{
310	char * pp = locate_parm(t,parm);
311	if(pp)
312	{
313		INT2 l = read_INT2(pp-2);
314		memcpy(v,pp,l-4);
315		*(v+l-4) = 0;
316		s->debug(2,"Received parm %d value %s\n",parm,v);
317
318		return TRUE;
319	}
320	return FALSE;
321}
322
323INT2 read_INT2(void *pp)
324{
325#ifdef __i386
326	return ntohs(*((INT2*)pp));
327#else
328	unsigned char * p = (unsigned char *)pp;
329	return (((INT2)(*p))<<8) + ((INT2)(*(p+1)));
330#endif
331}
332
333INT4 read_INT4(void *pp)
334{
335#ifdef __i386
336	return ntohl(*((INT4*)pp));
337#else
338	unsigned char * p = (unsigned char *)pp;
339	return (((INT4)(*p))<<24) + (((INT4)(*(p+1)))<<16) + (((INT4)(*(p+2)))<<8) + (((INT4)(*(p+3))));
340#endif
341}
342