]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/netdb.cc
* Merge in cygwin-64bit-branch.
[newlib-cygwin.git] / winsup / cygwin / netdb.cc
1 /* netdb.cc: network database related routines.
2
3 Copyright 2002, 2003, 2007, 2008, 2010, 2011, 2013 Red Hat, Inc.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include "winsup.h"
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <netdb.h>
15 #include <shared_info.h>
16
17 /* Locate and open a system network database file. relative_path
18 should be one of the following values:
19 "protocol"
20 "services"
21 "networks"
22 "hosts"
23
24 It is the callers responsibility to close the file. */
25 static FILE *
26 open_system_file (const char *relative_path)
27 {
28 /* system dir path is never longer. */
29 char win32_name[MAX_PATH];
30
31 user_shared->warned_msdos = true;
32 sys_wcstombs (win32_name, MAX_PATH, windows_system_directory);
33 strcat (win32_name, "drivers\\etc\\");
34 strcat (win32_name, relative_path);
35 FILE *result = fopen (win32_name, "rt");
36 debug_printf ("handle to netdb file %s: %p", win32_name, result);
37 return result;
38 }
39
40 inline static FILE *
41 open_protocol_file ()
42 {
43 return open_system_file ("protocol");
44 }
45
46 /* Wrapper for open_system_file(), fixing the constant name
47 "services". Returns the open file. */
48 inline static FILE *
49 open_services_file ()
50 {
51 return open_system_file ("services");
52 }
53
54 /* Read an entire line up till the next \n character. Memory for the
55 line is dynamically allocated, and the caller must call free() to
56 deallocate it. When the end of file is reached, NULL is returned. */
57 static char *
58 get_entire_line (FILE *fd)
59 {
60 static const int BUFF_SIZE = 1024;
61 struct line_fragment
62 {
63 char buffer[BUFF_SIZE];
64 line_fragment *next;
65 };
66
67 line_fragment *fragment_list_head = NULL;
68 line_fragment *fragment = NULL;
69 int fragment_count = 0;
70 char *result;
71
72 do
73 {
74 line_fragment *new_fragment = (line_fragment *) malloc (sizeof (line_fragment));
75 paranoid_printf ("line fragment allocated %p", new_fragment);
76 if (!fragment_list_head)
77 fragment_list_head = new_fragment;
78 if (fragment)
79 fragment->next = new_fragment;
80 fragment = new_fragment;
81 fragment->next = NULL;
82 *fragment->buffer = '\0';
83 result = fgets (fragment->buffer, BUFF_SIZE, fd);
84 ++fragment_count;
85 }
86 while (result && !strchr (fragment->buffer, '\n'));
87
88 if (*fragment_list_head->buffer != '\0')
89 {
90 char *concatenated_line = (char *) calloc (fragment_count * BUFF_SIZE , sizeof (char));
91 paranoid_printf ("concatenated line allocated %p", concatenated_line);
92 *concatenated_line = '\0';
93 fragment = fragment_list_head;
94 while (fragment != NULL)
95 {
96 line_fragment *previous = fragment;
97 strcat (concatenated_line, fragment->buffer);
98 fragment = fragment->next;
99 free (previous);
100 }
101 return concatenated_line;
102 }
103 else
104 {
105 fragment = fragment_list_head;
106 while (fragment != NULL)
107 {
108 line_fragment *previous = fragment;
109 fragment = fragment->next;
110 free (previous);
111 }
112 return NULL;
113 }
114 }
115
116 /* Characters representing whitespace. Used by parse_* routines to
117 delimit tokens. */
118 static const char *SPACE = " \t\n\r\f";
119
120 /* Parse a list aliases from a network database file. Returns a
121 char** structure terminated by a NULL. */
122 static void
123 parse_alias_list (char ***aliases, char **lasts)
124 {
125 struct alias_t
126 {
127 char *alias_name;
128 alias_t *next;
129 };
130 alias_t *alias_list_head = NULL, *alias_list_tail = NULL;
131 char *alias;
132 int alias_count = 0;
133 alias = strtok_r (NULL, SPACE, lasts);
134
135 while (alias)
136 {
137 ++alias_count;
138 alias_t *new_alias = (alias_t *) malloc (sizeof (alias_t));
139 paranoid_printf ("new alias alloc %p", new_alias);
140 if (!alias_list_head)
141 alias_list_head = new_alias;
142 if (alias_list_tail)
143 alias_list_tail->next = new_alias;
144 new_alias->next = NULL;
145 new_alias->alias_name = alias;
146 alias_list_tail = new_alias;
147 alias = strtok_r (NULL, SPACE, lasts);
148 }
149
150 *aliases = (char**) calloc (alias_count + 1, sizeof (char *));
151 paranoid_printf ("aliases alloc %p", *aliases);
152
153 char **current_entry = *aliases;
154 while (alias_list_head)
155 {
156 alias_t *previous = alias_list_head;
157 *current_entry = strdup (alias_list_head->alias_name);
158 paranoid_printf ("*current entry strdup %p", *current_entry);
159 alias_list_head = alias_list_head->next;
160 free (previous);
161 ++current_entry;
162 }
163
164 *current_entry = NULL;
165 }
166
167 /* Read the next line from svc_file, and parse it into the structure
168 pointed to by sep. sep can point to stack or static data, but it's
169 members will be overwritten with pointers to dynamically allocated
170 heap data accommodating parsed data. It is the responsibility of the
171 caller to free up the allocated structures. The function returns true
172 to indicate that a line was successfully read and parsed. False is
173 used to indicate that no more lines can be read and parsed. This
174 should also interpreted as end of file. */
175 static bool
176 parse_services_line (FILE *svc_file, struct servent *sep)
177 {
178 char *line;
179 while ((line = get_entire_line (svc_file)))
180 {
181 char *name, *port, *protocol, *lasts;
182
183 line[strcspn (line, "#")] = '\0'; // truncate at comment marker.
184 name = strtok_r (line, SPACE, &lasts);
185 if (!name)
186 {
187 free (line);
188 continue;
189 }
190 port = strtok_r (NULL, SPACE, &lasts);
191 protocol = strchr (port, '/');
192 *protocol++ = '\0';
193 sep->s_name = strdup (name);
194 paranoid_printf ("sep->s_name strdup %p", sep->s_name);
195 sep->s_port = atoi (port);
196 sep->s_proto = strdup (protocol);
197 paranoid_printf ("sep->s_proto strdup %p", sep->s_proto);
198 /* parse_alias_list relies on side effects. Read the comments
199 for that function.*/
200 parse_alias_list (& sep->s_aliases, &lasts);
201 free (line);
202 return true;
203 }
204 return false;
205 }
206
207 static FILE *svc_file = NULL;
208 static long int svc_read_pos = 0;
209 static struct servent current_servent;
210
211 /* Steps through a struct servent, and frees all of the internal
212 structures.*/
213 static void
214 free_servent (struct servent *sep)
215 {
216 free (sep->s_name);
217 free (sep->s_proto);
218 char ** current = sep->s_aliases;
219 while (current && *current)
220 {
221 free (*current);
222 ++current;
223 }
224 free (sep->s_aliases);
225 sep->s_name = NULL;
226 sep->s_port = 0;
227 sep->s_proto = NULL;
228 sep->s_aliases = NULL;
229 }
230
231 extern "C" void
232 cygwin_setservent (int stay_open)
233 {
234 if (svc_file)
235 fclose (svc_file);
236 if (stay_open)
237 svc_file = open_services_file ();
238 free_servent (&current_servent);
239 svc_read_pos = 0;
240 syscall_printf ("setservent (%d)", stay_open);
241 }
242
243 extern "C" struct servent *
244 cygwin_getservent (void)
245 {
246 FILE *fd;
247 if (svc_file)
248 fd = svc_file;
249 else
250 {
251 fd = open_services_file ();
252 if (!fd)
253 {
254 syscall_printf ("%p = getservent()", NULL);
255 return NULL;
256 }
257 fseek (fd, svc_read_pos, SEEK_SET);
258 }
259 free_servent (&current_servent);
260 bool found = parse_services_line (fd, &current_servent);
261 if (!svc_file)
262 {
263 svc_read_pos = ftell (fd);
264 fclose (fd);
265 }
266 struct servent *result;
267 if (found)
268 result = &current_servent;
269 else
270 result = NULL;
271 syscall_printf ("%p = getservent()", result);
272 return result;
273 }
274
275 extern "C" void
276 cygwin_endservent (void)
277 {
278 if (svc_file)
279 {
280 fclose (svc_file);
281 svc_file = NULL;
282 }
283 free_servent (&current_servent);
284 svc_read_pos = 0;
285 syscall_printf ("endservent ()");
286 }
287
288 /* Read the next line from proto_file, and parse it into the structure
289 pointed to by pep. pep can point to stack or static data, but it's
290 members will be overwritten with pointers to dynamically allocated
291 heap data accommodating parsed data. It is the responsibility of the
292 caller to free up the allocated structures. The function returns true
293 to indicate that a line was successfully read and parsed. False is
294 used to indicate that no more lines can be read and parsed. This
295 should also interpreted as end of file. */
296 static bool
297 parse_protocol_line (FILE *proto_file, struct protoent *pep)
298 {
299 char *line;
300 while ((line = get_entire_line (proto_file)))
301 {
302 char *name, *protocol, *lasts;
303
304 line[strcspn (line, "#")] = '\0'; // truncate at comment marker.
305 name = strtok_r (line, SPACE, &lasts);
306 if (!name)
307 {
308 free (line);
309 continue;
310 }
311 protocol = strtok_r (NULL, SPACE, &lasts);
312 pep->p_name = strdup (name);
313 paranoid_printf ("pep->p_name strdup %p", pep->p_name);
314 pep->p_proto = atoi (protocol);
315 /* parse_alias_list relies on side effects. Read the comments
316 for that function.*/
317 parse_alias_list (& pep->p_aliases, &lasts);
318 free (line);
319 return true;
320 }
321 return false;
322 }
323
324 static FILE *proto_file = NULL;
325 static long int proto_read_pos = 0;
326 static struct protoent current_protoent;
327
328 /* Steps through a struct protoent, and frees all the internal
329 structures. */
330 static void
331 free_protoent (struct protoent *pep)
332 {
333 free (pep->p_name);
334 char ** current = pep->p_aliases;
335 while (current && *current)
336 {
337 free (*current);
338 ++current;
339 }
340 free (pep->p_aliases);
341 pep->p_name = NULL;
342 pep->p_proto = 0;
343 pep->p_aliases = NULL;
344 }
345
346 extern "C" void
347 cygwin_setprotoent (int stay_open)
348 {
349 if (proto_file)
350 fclose (proto_file);
351
352 if (stay_open)
353 proto_file = open_protocol_file ();
354
355 free_protoent (&current_protoent);
356 proto_read_pos = 0;
357 syscall_printf ("setprotoent (%d)", stay_open);
358 }
359
360 extern "C" struct protoent *
361 cygwin_getprotoent (void)
362 {
363 FILE *fd;
364
365 if (proto_file)
366 fd = proto_file;
367 else
368 {
369 fd = open_protocol_file ();
370 if (!fd)
371 {
372 syscall_printf ("%p = getprotoent()", NULL);
373 return NULL;
374 }
375 fseek (fd, proto_read_pos, SEEK_SET);
376 }
377 free_protoent (&current_protoent);
378
379 bool found = parse_protocol_line (fd, &current_protoent);
380 if (!proto_file)
381 {
382 proto_read_pos = ftell (fd);
383 fclose (fd);
384 }
385
386 struct protoent *result;
387 if (found)
388 result = &current_protoent;
389 else
390 result = NULL;
391
392 syscall_printf ("%p = getprotoent()", result);
393 return result;
394 }
395
396 extern "C" void
397 cygwin_endprotoent (void)
398 {
399 if (proto_file)
400 {
401 fclose (proto_file);
402 proto_file = NULL;
403 }
404
405 free_protoent (&current_protoent);
406 proto_read_pos = 0;
407 syscall_printf ("endprotoent ()");
408 }
This page took 0.051407 seconds and 5 git commands to generate.