1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  *
22  * Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
28  * All Rights Reserved.
29  */
30 
31 /*
32  * University Copyright- Copyright (c) 1982, 1986, 1988
33  * The Regents of the University of California.
34  * All Rights Reserved.
35  *
36  * University Acknowledgment- Portions of this document are derived from
37  * software developed by the University of California, Berkeley, and its
38  * contributors.
39  */
40 
41 /*
42  * Routines to handle insertion, deletion, etc on the table
43  * of requests kept by the daemon. Nothing fancy here, linear
44  * search on a double-linked list. A time is kept with each
45  * entry so that overly old invitations can be eliminated.
46  *
47  * Consider this a mis-guided attempt at modularity
48  */
49 
50 #include <sys/time.h>
51 #include <string.h>
52 #include <stdio.h>
53 #include <malloc.h>
54 #include "talkd_impl.h"
55 
56 #define	MAX_ID 16000 /* << 2^15 so I don't have sign troubles */
57 
58 typedef struct table_entry TABLE_ENTRY;
59 
60 struct table_entry {
61     CTL_MSG request;
62     long time;
63     TABLE_ENTRY *next;
64     TABLE_ENTRY *last;
65 };
66 
67 static struct timeval tp;
68 static TABLE_ENTRY *table = NULL;
69 
70 static void delete(TABLE_ENTRY *ptr);
71 
72 /*
73  * Look in the table for an invitation that matches the current
74  * request looking for an invitation.
75  */
76 
77 CTL_MSG *
find_match(CTL_MSG * request)78 find_match(CTL_MSG *request)
79 {
80 	TABLE_ENTRY *ptr;
81 	TABLE_ENTRY *prevp;
82 	long current_time;
83 
84 	(void) gettimeofday(&tp, NULL);
85 	current_time = tp.tv_sec;
86 
87 	ptr = table;
88 
89 	if (debug) {
90 		(void) printf("Entering Look-Up with : \n");
91 		print_request(request);
92 	}
93 
94 	while (ptr != NULL) {
95 
96 		if ((ptr->time - current_time) > MAX_LIFE) {
97 		/* the entry is too old */
98 			if (debug) {
99 				(void) printf("Deleting expired entry : \n");
100 				print_request(&ptr->request);
101 			}
102 			prevp = ptr;
103 			ptr = ptr->next;
104 			delete(prevp);
105 			continue;
106 		}
107 
108 		if (debug)
109 			print_request(&ptr->request);
110 
111 		if (strcmp(request->l_name, ptr->request.r_name) == 0 &&
112 		    strcmp(request->r_name, ptr->request.l_name) == 0 &&
113 		    ptr->request.type == LEAVE_INVITE) {
114 			return (&ptr->request);
115 		}
116 
117 		ptr = ptr->next;
118 	}
119 
120 	return (NULL);
121 }
122 
123 /*
124  * Look for an identical request, as opposed to a complimentary
125  * one as find_match does.
126  */
127 
128 CTL_MSG *
find_request(CTL_MSG * request)129 find_request(CTL_MSG *request)
130 {
131 	TABLE_ENTRY *ptr;
132 	TABLE_ENTRY *prevp;
133 	long current_time;
134 
135 	(void) gettimeofday(&tp, NULL);
136 	current_time = tp.tv_sec;
137 
138 	/*
139 	 * See if this is a repeated message, and check for
140 	 * out of date entries in the table while we are it.
141 	 */
142 
143 	ptr = table;
144 
145 	if (debug) {
146 		(void) printf("Entering find_request with : \n");
147 		print_request(request);
148 	}
149 
150 	while (ptr != NULL) {
151 
152 		if ((ptr->time - current_time) > MAX_LIFE) {
153 			/* the entry is too old */
154 			if (debug) {
155 				(void) printf("Deleting expired entry : \n");
156 				print_request(&ptr->request);
157 			}
158 			prevp = ptr;
159 			ptr = ptr->next;
160 			delete(prevp);
161 			continue;
162 		}
163 
164 		if (debug)
165 			print_request(&ptr->request);
166 
167 		if (strcmp(request->r_name, ptr->request.r_name) == 0 &&
168 		    strcmp(request->l_name, ptr->request.l_name) == 0 &&
169 		    request->type == ptr->request.type &&
170 		    request->pid == ptr->request.pid) {
171 
172 			/* update the time if we 'touch' it */
173 			ptr->time = current_time;
174 			return (&ptr->request);
175 		}
176 
177 		ptr = ptr->next;
178 	}
179 
180 	return (NULL);
181 }
182 
183 void
insert_table(CTL_MSG * request,CTL_RESPONSE * response)184 insert_table(CTL_MSG *request, CTL_RESPONSE *response)
185 {
186 	TABLE_ENTRY *ptr;
187 	long current_time;
188 
189 	(void) gettimeofday(&tp, NULL);
190 	current_time = tp.tv_sec;
191 
192 	response->id_num = request->id_num = new_id();
193 
194 	/*
195 	 * Insert a new entry into the top of the list.
196 	 */
197 	ptr = (TABLE_ENTRY *) malloc(sizeof (TABLE_ENTRY));
198 
199 	if (ptr == NULL) {
200 		print_error("malloc in insert_table");
201 	}
202 
203 	ptr->time = current_time;
204 	ptr->request = *request;
205 
206 	ptr->next = table;
207 	if (ptr->next != NULL) {
208 		ptr->next->last = ptr;
209 	}
210 	ptr->last = NULL;
211 	table = ptr;
212 }
213 
214 /*
215  * Generate a unique non-zero sequence number.
216  */
217 
218 int
new_id(void)219 new_id(void)
220 {
221 	static int current_id = 0;
222 
223 	current_id = (current_id + 1) % MAX_ID;
224 
225 	/* 0 is reserved, helps to pick up bugs */
226 	if (current_id == 0)
227 		current_id = 1;
228 
229 	return (current_id);
230 }
231 
232 /*
233  * Delete the invitation with id 'id_num'.
234  */
235 
236 int
delete_invite(int id_num)237 delete_invite(int id_num)
238 {
239 	TABLE_ENTRY *ptr;
240 
241 	ptr = table;
242 
243 	if (debug)
244 		(void) printf("Entering delete_invite with %d\n", id_num);
245 
246 	while (ptr != NULL && ptr->request.id_num != id_num) {
247 		if (debug)
248 			print_request(&ptr->request);
249 		ptr = ptr->next;
250 	}
251 
252 	if (ptr != NULL) {
253 		delete(ptr);
254 		return (SUCCESS);
255 	}
256 
257 	return (NOT_HERE);
258 }
259 
260 /*
261  * Classic delete from a double-linked list.
262  */
263 
264 static void
delete(TABLE_ENTRY * ptr)265 delete(TABLE_ENTRY *ptr)
266 {
267 	if (debug) {
268 		(void) printf("Deleting : ");
269 		print_request(&ptr->request);
270 	}
271 	if (table == ptr) {
272 		table = ptr->next;
273 	} else if (ptr->last != NULL) {
274 		ptr->last->next = ptr->next;
275 	}
276 
277 	if (ptr->next != NULL) {
278 		ptr->next->last = ptr->last;
279 	}
280 
281 	free(ptr);
282 }
283