]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/netdb.cc
Throughout, update copyrights to reflect dates which correspond to main-branch
[newlib-cygwin.git] / winsup / cygwin / netdb.cc
CommitLineData
838ad582
CF
1/* netdb.cc: network database related routines.
2
bc837d22 3 Copyright 2002, 2003, 2007, 2008, 2010, 2011 Red Hat, Inc.
838ad582
CF
4
5This file is part of Cygwin.
6
7This software is a copyrighted work licensed under the terms of the
8Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9details. */
10
11#include "winsup.h"
838ad582 12#include <stdio.h>
838ad582
CF
13#include <stdlib.h>
14#include <netdb.h>
8d1bda71 15#include <shared_info.h>
838ad582
CF
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
838ad582
CF
24 It is the callers responsibility to close the file. */
25static FILE *
26open_system_file (const char *relative_path)
27{
27114d3a
CV
28 /* system dir path is never longer. */
29 char win32_name[MAX_PATH];
570858c3 30
8d1bda71 31 user_shared->warned_msdos = true;
893a8b78
CV
32 sys_wcstombs (win32_name, MAX_PATH, windows_system_directory);
33 strcat (win32_name, "drivers\\etc\\");
838ad582 34 strcat (win32_name, relative_path);
27114d3a 35 FILE *result = fopen (win32_name, "rt");
893a8b78 36 debug_printf ("handle to netdb file %s: %p", win32_name, result);
838ad582
CF
37 return result;
38}
39
40inline static FILE *
41open_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. */
48inline static FILE *
49open_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
55line is dynamically allocated, and the caller must call free() to
56deallocate it. When the end of file is reached, NULL is returned. */
57static char *
58get_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
117delimit tokens. */
118static const NO_COPY char *SPACE = " \t\n\r\f";
119
120/* Parse a list aliases from a network database file. Returns a
b60e545b 121char** structure terminated by a NULL. */
838ad582 122static void
bb241345 123parse_alias_list (char ***aliases, char **lasts)
838ad582
CF
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;
bb241345 133 alias = strtok_r (NULL, SPACE, lasts);
838ad582
CF
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;
bb241345 147 alias = strtok_r (NULL, SPACE, lasts);
838ad582
CF
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
168pointed to by sep. sep can point to stack or static data, but it's
169members will be overwritten with pointers to dynamically allocated
170heap data accommodating parsed data. It is the responsibility of the
171caller to free up the allocated structures. The function returns true
172to indicate that a line was successfully read and parsed. False is
173used to indicate that no more lines can be read and parsed. This
174should also interpreted as end of file. */
175static bool
176parse_services_line (FILE *svc_file, struct servent *sep)
177{
178 char *line;
179 while ((line = get_entire_line (svc_file)))
180 {
bb241345 181 char *name, *port, *protocol, *lasts;
838ad582
CF
182
183 line[strcspn (line, "#")] = '\0'; // truncate at comment marker.
bb241345 184 name = strtok_r (line, SPACE, &lasts);
838ad582
CF
185 if (!name)
186 {
187 free (line);
188 continue;
189 }
bb241345 190 port = strtok_r (NULL, SPACE, &lasts);
838ad582
CF
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.*/
bb241345 200 parse_alias_list (& sep->s_aliases, &lasts);
838ad582
CF
201 free (line);
202 return true;
203 }
204 return false;
205}
206
207static FILE *svc_file = NULL;
208static long int svc_read_pos = 0;
209static struct servent current_servent;
210
211/* Steps through a struct servent, and frees all of the internal
212structures.*/
213static void
214free_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
231extern "C" void
232cygwin_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
243extern "C" struct servent *
244cygwin_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
275extern "C" void
276cygwin_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
289pointed to by pep. pep can point to stack or static data, but it's
290members will be overwritten with pointers to dynamically allocated
291heap data accommodating parsed data. It is the responsibility of the
292caller to free up the allocated structures. The function returns true
293to indicate that a line was successfully read and parsed. False is
294used to indicate that no more lines can be read and parsed. This
295should also interpreted as end of file. */
296static bool
297parse_protocol_line (FILE *proto_file, struct protoent *pep)
298{
299 char *line;
300 while ((line = get_entire_line (proto_file)))
301 {
bb241345 302 char *name, *protocol, *lasts;
838ad582
CF
303
304 line[strcspn (line, "#")] = '\0'; // truncate at comment marker.
bb241345 305 name = strtok_r (line, SPACE, &lasts);
838ad582
CF
306 if (!name)
307 {
308 free (line);
309 continue;
310 }
bb241345 311 protocol = strtok_r (NULL, SPACE, &lasts);
838ad582
CF
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.*/
bb241345 317 parse_alias_list (& pep->p_aliases, &lasts);
838ad582
CF
318 free (line);
319 return true;
320 }
321 return false;
322}
323
324static FILE *proto_file = NULL;
325static long int proto_read_pos = 0;
326static struct protoent current_protoent;
327
328/* Steps through a struct protoent, and frees all the internal
329structures. */
330static void
331free_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
346extern "C" void
347cygwin_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
360extern "C" struct protoent *
361cygwin_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
396extern "C" void
397cygwin_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.358328 seconds and 5 git commands to generate.