blob: f04fbde4c7263af307df9a18589c067202c77121 [file] [log] [blame]
njneb8896b2005-06-04 20:03:55 +00001
2/*--------------------------------------------------------------------*/
3/*--- File- and socket-related libc stuff. m_libcfile.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
sewardj9ebd6e02007-01-08 06:01:59 +000010 Copyright (C) 2000-2007 Julian Seward
njneb8896b2005-06-04 20:03:55 +000011 jseward@acm.org
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
njnc7561b92005-06-19 01:24:32 +000031#include "pub_core_basics.h"
sewardj4cfea4f2006-10-14 19:26:10 +000032#include "pub_core_vki.h"
sewardj9a66bb92006-10-17 01:38:13 +000033#include "pub_core_vkiscnums.h"
sewardj26b87282006-10-17 12:49:31 +000034#include "pub_core_debuglog.h"
njneb8896b2005-06-04 20:03:55 +000035#include "pub_core_libcbase.h"
36#include "pub_core_libcassert.h"
37#include "pub_core_libcfile.h"
sewardjfdf91b42005-09-28 00:53:09 +000038#include "pub_core_libcprint.h" // VG_(sprintf)
sewardj45f4e7c2005-09-27 19:20:21 +000039#include "pub_core_libcproc.h" // VG_(getpid), VG_(getppid)
sewardj14c7cc52007-02-25 15:08:24 +000040#include "pub_core_xarray.h"
sewardjfdf91b42005-09-28 00:53:09 +000041#include "pub_core_clientstate.h" // VG_(fd_hard_limit)
njn9abd6082005-06-17 21:31:45 +000042#include "pub_core_syscall.h"
njneb8896b2005-06-04 20:03:55 +000043
44/* ---------------------------------------------------------------------
45 File stuff
46 ------------------------------------------------------------------ */
47
48static inline Bool fd_exists(Int fd)
49{
50 struct vki_stat st;
51
52 return VG_(fstat)(fd, &st) == 0;
53}
54
55/* Move an fd into the Valgrind-safe range */
56Int VG_(safe_fd)(Int oldfd)
57{
58 Int newfd;
59
60 vg_assert(VG_(fd_hard_limit) != -1);
61
62 newfd = VG_(fcntl)(oldfd, VKI_F_DUPFD, VG_(fd_hard_limit));
63 if (newfd != -1)
64 VG_(close)(oldfd);
65
sewardj9a66bb92006-10-17 01:38:13 +000066 /* Set the close-on-exec flag for this fd. */
njneb8896b2005-06-04 20:03:55 +000067 VG_(fcntl)(newfd, VKI_F_SETFD, VKI_FD_CLOEXEC);
68
69 vg_assert(newfd >= VG_(fd_hard_limit));
70 return newfd;
71}
72
njnae7359b2005-06-19 21:10:42 +000073/* Given a file descriptor, attempt to deduce its filename. To do
74 this, we use /proc/self/fd/<FD>. If this doesn't point to a file,
njnf845f8f2005-06-23 02:26:47 +000075 or if it doesn't exist, we return False. */
76Bool VG_(resolve_filename) ( Int fd, HChar* buf, Int n_buf )
njnae7359b2005-06-19 21:10:42 +000077{
78 HChar tmp[64];
79
80 VG_(sprintf)(tmp, "/proc/self/fd/%d", fd);
njnf845f8f2005-06-23 02:26:47 +000081 VG_(memset)(buf, 0, n_buf);
njnae7359b2005-06-19 21:10:42 +000082
sewardj45f4e7c2005-09-27 19:20:21 +000083 if (VG_(readlink)(tmp, buf, n_buf) > 0 && buf[0] == '/')
njnf845f8f2005-06-23 02:26:47 +000084 return True;
85 else
86 return False;
njnae7359b2005-06-19 21:10:42 +000087}
88
sewardj92645592005-07-23 09:18:34 +000089SysRes VG_(open) ( const Char* pathname, Int flags, Int mode )
njneb8896b2005-06-04 20:03:55 +000090{
sewardja8d8e232005-06-07 20:04:56 +000091 SysRes res = VG_(do_syscall3)(__NR_open, (UWord)pathname, flags, mode);
sewardj92645592005-07-23 09:18:34 +000092 return res;
njneb8896b2005-06-04 20:03:55 +000093}
94
95void VG_(close) ( Int fd )
96{
sewardja8d8e232005-06-07 20:04:56 +000097 (void)VG_(do_syscall1)(__NR_close, fd);
njneb8896b2005-06-04 20:03:55 +000098}
99
100Int VG_(read) ( Int fd, void* buf, Int count)
101{
sewardj9a66bb92006-10-17 01:38:13 +0000102 Int ret;
sewardja8d8e232005-06-07 20:04:56 +0000103 SysRes res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count);
sewardj9a66bb92006-10-17 01:38:13 +0000104 if (res.isError) {
105 ret = - (Int)(Word)res.err;
106 vg_assert(ret < 0);
107 } else {
108 ret = (Int)(Word)res.res;
109 vg_assert(ret >= 0);
110 }
111 return ret;
njneb8896b2005-06-04 20:03:55 +0000112}
113
114Int VG_(write) ( Int fd, const void* buf, Int count)
115{
sewardj9a66bb92006-10-17 01:38:13 +0000116 Int ret;
sewardja8d8e232005-06-07 20:04:56 +0000117 SysRes res = VG_(do_syscall3)(__NR_write, fd, (UWord)buf, count);
sewardj9a66bb92006-10-17 01:38:13 +0000118 if (res.isError) {
119 ret = - (Int)(Word)res.err;
120 vg_assert(ret < 0);
121 } else {
122 ret = (Int)(Word)res.res;
123 vg_assert(ret >= 0);
124 }
125 return ret;
njneb8896b2005-06-04 20:03:55 +0000126}
127
128Int VG_(pipe) ( Int fd[2] )
129{
sewardja8d8e232005-06-07 20:04:56 +0000130 SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd);
131 return res.isError ? -1 : 0;
njneb8896b2005-06-04 20:03:55 +0000132}
133
sewardj45f4e7c2005-09-27 19:20:21 +0000134OffT VG_(lseek) ( Int fd, OffT offset, Int whence )
njneb8896b2005-06-04 20:03:55 +0000135{
sewardja8d8e232005-06-07 20:04:56 +0000136 SysRes res = VG_(do_syscall3)(__NR_lseek, fd, offset, whence);
sewardj9a66bb92006-10-17 01:38:13 +0000137 return res.isError ? (-1) : res.res;
sewardj45f4e7c2005-09-27 19:20:21 +0000138 /* if you change the error-reporting conventions of this, also
139 change VG_(pread) and all other usage points. */
njneb8896b2005-06-04 20:03:55 +0000140}
141
tom6c93c4f2005-08-05 07:46:32 +0000142SysRes VG_(stat) ( Char* file_name, struct vki_stat* buf )
njneb8896b2005-06-04 20:03:55 +0000143{
sewardj9a66bb92006-10-17 01:38:13 +0000144# if defined(VGO_linux)
sewardja8d8e232005-06-07 20:04:56 +0000145 SysRes res = VG_(do_syscall2)(__NR_stat, (UWord)file_name, (UWord)buf);
tom6c93c4f2005-08-05 07:46:32 +0000146 return res;
sewardj9a66bb92006-10-17 01:38:13 +0000147# elif defined(VGO_aix5)
148 SysRes res = VG_(do_syscall4)(__NR_AIX5_statx,
149 (UWord)file_name,
150 (UWord)buf,
151 sizeof(struct vki_stat),
152 VKI_STX_NORMAL);
153 return res;
154# else
155# error Unknown OS
156# endif
njneb8896b2005-06-04 20:03:55 +0000157}
158
159Int VG_(fstat) ( Int fd, struct vki_stat* buf )
160{
sewardj9a66bb92006-10-17 01:38:13 +0000161# if defined(VGO_linux)
sewardja8d8e232005-06-07 20:04:56 +0000162 SysRes res = VG_(do_syscall2)(__NR_fstat, fd, (UWord)buf);
163 return res.isError ? (-1) : 0;
sewardj9a66bb92006-10-17 01:38:13 +0000164# elif defined(VGO_aix5)
165 I_die_here;
166# else
167# error Unknown OS
168# endif
njneb8896b2005-06-04 20:03:55 +0000169}
170
sewardj45f4e7c2005-09-27 19:20:21 +0000171Int VG_(fsize) ( Int fd )
njneb8896b2005-06-04 20:03:55 +0000172{
sewardj9a66bb92006-10-17 01:38:13 +0000173# if defined(VGO_linux) && defined(__NR_fstat64)
tom574b8932006-07-05 17:47:46 +0000174 struct vki_stat64 buf;
175 SysRes res = VG_(do_syscall2)(__NR_fstat64, fd, (UWord)&buf);
sewardj9a66bb92006-10-17 01:38:13 +0000176 return res.isError ? (-1) : buf.st_size;
177# elif defined(VGO_linux) && !defined(__NR_fstat64)
sewardj45f4e7c2005-09-27 19:20:21 +0000178 struct vki_stat buf;
179 SysRes res = VG_(do_syscall2)(__NR_fstat, fd, (UWord)&buf);
180 return res.isError ? (-1) : buf.st_size;
sewardj9a66bb92006-10-17 01:38:13 +0000181# elif defined(VGO_aix5)
182 I_die_here;
183# else
184# error Unknown OS
185# endif
sewardj45f4e7c2005-09-27 19:20:21 +0000186}
187
njn73750612005-10-14 03:11:30 +0000188Bool VG_(is_dir) ( HChar* f )
189{
190 struct vki_stat buf;
sewardj9a66bb92006-10-17 01:38:13 +0000191 SysRes res = VG_(stat)(f, &buf);
njn73750612005-10-14 03:11:30 +0000192 return res.isError ? False
193 : VKI_S_ISDIR(buf.st_mode) ? True : False;
194}
195
sewardj45f4e7c2005-09-27 19:20:21 +0000196SysRes VG_(dup) ( Int oldfd )
197{
198 return VG_(do_syscall1)(__NR_dup, oldfd);
njneb8896b2005-06-04 20:03:55 +0000199}
200
njn327fe8a2005-06-12 02:49:35 +0000201/* Returns -1 on error. */
202Int VG_(fcntl) ( Int fd, Int cmd, Int arg )
203{
204 SysRes res = VG_(do_syscall3)(__NR_fcntl, fd, cmd, arg);
sewardj9a66bb92006-10-17 01:38:13 +0000205 return res.isError ? -1 : res.res;
njn327fe8a2005-06-12 02:49:35 +0000206}
207
njneb8896b2005-06-04 20:03:55 +0000208Int VG_(rename) ( Char* old_name, Char* new_name )
209{
sewardja8d8e232005-06-07 20:04:56 +0000210 SysRes res = VG_(do_syscall2)(__NR_rename, (UWord)old_name, (UWord)new_name);
211 return res.isError ? (-1) : 0;
njneb8896b2005-06-04 20:03:55 +0000212}
213
214Int VG_(unlink) ( Char* file_name )
215{
sewardja8d8e232005-06-07 20:04:56 +0000216 SysRes res = VG_(do_syscall1)(__NR_unlink, (UWord)file_name);
217 return res.isError ? (-1) : 0;
njneb8896b2005-06-04 20:03:55 +0000218}
219
sewardj198f34f2007-07-09 23:13:07 +0000220/* The working directory at startup. AIX doesn't provide an easy
221 system call to do getcwd, but fortunately we don't need arbitrary
222 getcwd support. All that is really needed is to note the cwd at
223 process startup. Hence VG_(record_startup_wd) notes it (in a
224 platform dependent way) and VG_(get_startup_wd) produces the noted
225 value. Hence: */
226static HChar startup_wd[VKI_PATH_MAX];
227static Bool startup_wd_acquired = False;
228
229/* Record the process' working directory at startup. Is intended to
230 be called exactly once, at startup, before the working directory
231 changes. Return True for success, False for failure, so that the
232 caller can bomb out suitably without creating module cycles if
233 there is a problem. */
234Bool VG_(record_startup_wd) ( void )
njneb8896b2005-06-04 20:03:55 +0000235{
sewardj198f34f2007-07-09 23:13:07 +0000236 const Int szB = sizeof(startup_wd);
237 vg_assert(!startup_wd_acquired);
238 vg_assert(szB >= 512 && szB <= 16384/*let's say*/); /* stay sane */
239 VG_(memset)(startup_wd, 0, szB);
sewardj9a66bb92006-10-17 01:38:13 +0000240# if defined(VGO_linux)
sewardj198f34f2007-07-09 23:13:07 +0000241 /* Simple: just ask the kernel */
242 { SysRes res
243 = VG_(do_syscall2)(__NR_getcwd, (UWord)startup_wd, szB-1);
244 vg_assert(startup_wd[szB-1] == 0);
245 if (res.isError) {
246 return False;
247 } else {
248 startup_wd_acquired = True;
249 return True;
250 }
251 }
sewardj9a66bb92006-10-17 01:38:13 +0000252# elif defined(VGO_aix5)
sewardj198f34f2007-07-09 23:13:07 +0000253 /* We can't ask the kernel, so instead rely on launcher-aix5.c to
254 tell us the startup path. Note the env var is keyed to the
255 parent's PID, not ours, since our parent is the launcher
256 process. */
257 { Char envvar[100];
258 Char* wd = NULL;
259 VG_(memset)(envvar, 0, sizeof(envvar));
260 VG_(sprintf)(envvar, "VALGRIND_STARTUP_PWD_%d_XYZZY",
261 (Int)VG_(getppid)());
262 wd = VG_(getenv)( envvar );
263 if (wd == NULL || (1+VG_(strlen)(wd) >= szB))
264 return False;
265 VG_(strncpy_safely)(startup_wd, wd, szB);
266 vg_assert(startup_wd[szB-1] == 0);
267 startup_wd_acquired = True;
268 return True;
269 }
sewardj9a66bb92006-10-17 01:38:13 +0000270# else
271# error Unknown OS
272# endif
njneb8896b2005-06-04 20:03:55 +0000273}
274
sewardj198f34f2007-07-09 23:13:07 +0000275/* Copy the previously acquired startup_wd into buf[0 .. size-1],
276 or return False if buf isn't big enough. */
277Bool VG_(get_startup_wd) ( Char* buf, SizeT size )
278{
279 vg_assert(startup_wd_acquired);
280 vg_assert(startup_wd[ sizeof(startup_wd)-1 ] == 0);
281 if (1+VG_(strlen)(startup_wd) >= size)
282 return False;
283 VG_(strncpy_safely)(buf, startup_wd, size);
284 return True;
285}
286
njneb8896b2005-06-04 20:03:55 +0000287Int VG_(readlink) (Char* path, Char* buf, UInt bufsiz)
288{
sewardja8d8e232005-06-07 20:04:56 +0000289 SysRes res;
njneb8896b2005-06-04 20:03:55 +0000290 /* res = readlink( path, buf, bufsiz ); */
291 res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
sewardj9a66bb92006-10-17 01:38:13 +0000292 return res.isError ? -1 : res.res;
njneb8896b2005-06-04 20:03:55 +0000293}
294
295Int VG_(getdents) (UInt fd, struct vki_dirent *dirp, UInt count)
296{
sewardja8d8e232005-06-07 20:04:56 +0000297 SysRes res;
njneb8896b2005-06-04 20:03:55 +0000298 /* res = getdents( fd, dirp, count ); */
299 res = VG_(do_syscall3)(__NR_getdents, fd, (UWord)dirp, count);
sewardj9a66bb92006-10-17 01:38:13 +0000300 return res.isError ? -1 : res.res;
njneb8896b2005-06-04 20:03:55 +0000301}
302
sewardj45f4e7c2005-09-27 19:20:21 +0000303/* Check accessibility of a file. Returns zero for access granted,
304 nonzero otherwise. */
305Int VG_(access) ( HChar* path, Bool irusr, Bool iwusr, Bool ixusr )
306{
sewardj9a66bb92006-10-17 01:38:13 +0000307# if defined(VGO_linux)
sewardj45f4e7c2005-09-27 19:20:21 +0000308 /* Very annoyingly, I cannot find any definition for R_OK et al in
309 the kernel interfaces. Therefore I reluctantly resort to
310 hardwiring in these magic numbers that I determined by
311 experimentation. */
312 UWord w = (irusr ? 4/*R_OK*/ : 0)
313 | (iwusr ? 2/*W_OK*/ : 0)
314 | (ixusr ? 1/*X_OK*/ : 0);
315 SysRes res = VG_(do_syscall2)(__NR_access, (UWord)path, w);
sewardj9a66bb92006-10-17 01:38:13 +0000316 return res.isError ? 1 : 0;
317# elif defined(VGO_aix5)
318 UWord w = (irusr ? VKI_R_OK : 0)
319 | (iwusr ? VKI_W_OK : 0)
320 | (ixusr ? VKI_X_OK : 0);
321 SysRes res = VG_(do_syscall2)(__NR_access, (UWord)path, w);
322 return res.isError ? 1 : 0;
323# else
324# error "Don't know how to do VG_(access) on this OS"
325# endif
sewardj45f4e7c2005-09-27 19:20:21 +0000326}
327
njn73750612005-10-14 03:11:30 +0000328/*
329 Emulate the normal Unix permissions checking algorithm.
330
331 If owner matches, then use the owner permissions, else
332 if group matches, then use the group permissions, else
333 use other permissions.
334
335 Note that we can't deal with SUID/SGID, so we refuse to run them
336 (otherwise the executable may misbehave if it doesn't have the
337 permissions it thinks it does).
338*/
339/* returns: 0 = success, non-0 is failure */
340Int VG_(check_executable)(HChar* f)
341{
sewardj26b87282006-10-17 12:49:31 +0000342 /* This is something of a kludge. Really we should fix VG_(stat) to
343 do this itself, but not clear how to do it as it depends on
344 having a 'struct vki_stat64' which is different from 'struct
345 vki_stat'. */
346# if defined(VGO_linux) && defined(__NR_stat64)
toma346c262006-09-29 08:12:08 +0000347 struct vki_stat64 st;
348 SysRes res = VG_(do_syscall2)(__NR_stat64, (UWord)f, (UWord)&st);
sewardj26b87282006-10-17 12:49:31 +0000349# else
njn73750612005-10-14 03:11:30 +0000350 struct vki_stat st;
sewardj26b87282006-10-17 12:49:31 +0000351 SysRes res = VG_(stat)(f, &st);
352# endif
njn73750612005-10-14 03:11:30 +0000353
njn73750612005-10-14 03:11:30 +0000354 if (res.isError) {
sewardj9a66bb92006-10-17 01:38:13 +0000355 return res.err;
njn73750612005-10-14 03:11:30 +0000356 }
357
358 if (st.st_mode & (VKI_S_ISUID | VKI_S_ISGID)) {
sewardj9a66bb92006-10-17 01:38:13 +0000359 /* VG_(printf)("Can't execute suid/sgid executable %s\n", exe); */
njn73750612005-10-14 03:11:30 +0000360 return VKI_EACCES;
361 }
362
363 if (VG_(geteuid)() == st.st_uid) {
364 if (!(st.st_mode & VKI_S_IXUSR))
365 return VKI_EACCES;
366 } else {
sewardj45406ef2006-10-18 00:33:46 +0000367 Int grpmatch = 0;
njn73750612005-10-14 03:11:30 +0000368
369 if (VG_(getegid)() == st.st_gid)
370 grpmatch = 1;
371 else {
372 UInt groups[32];
373 Int ngrp = VG_(getgroups)(32, groups);
374 Int i;
375 /* ngrp will be -1 if VG_(getgroups) failed. */
376 for (i = 0; i < ngrp; i++) {
377 if (groups[i] == st.st_gid) {
378 grpmatch = 1;
379 break;
380 }
381 }
382 }
383
384 if (grpmatch) {
385 if (!(st.st_mode & VKI_S_IXGRP)) {
386 return VKI_EACCES;
387 }
388 } else if (!(st.st_mode & VKI_S_IXOTH)) {
389 return VKI_EACCES;
390 }
391 }
392
393 return 0;
394}
395
sewardj45f4e7c2005-09-27 19:20:21 +0000396SysRes VG_(pread) ( Int fd, void* buf, Int count, Int offset )
397{
398 OffT off = VG_(lseek)( fd, (OffT)offset, VKI_SEEK_SET);
tomf4c23102005-10-31 17:05:21 +0000399 if (off < 0)
sewardj45f4e7c2005-09-27 19:20:21 +0000400 return VG_(mk_SysRes_Error)( VKI_EINVAL );
tom60a4b0b2005-10-12 10:45:27 +0000401 return VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count );
sewardj45f4e7c2005-09-27 19:20:21 +0000402}
403
404/* Create and open (-rw------) a tmp file name incorporating said arg.
405 Returns -1 on failure, else the fd of the file. If fullname is
406 non-NULL, the file's name is written into it. The number of bytes
407 written is guaranteed not to exceed 64+strlen(part_of_name). */
408
409Int VG_(mkstemp) ( HChar* part_of_name, /*OUT*/HChar* fullname )
410{
411 HChar buf[200];
412 Int n, tries, fd;
413 UInt seed;
414 SysRes sres;
415
416 vg_assert(part_of_name);
417 n = VG_(strlen)(part_of_name);
418 vg_assert(n > 0 && n < 100);
419
420 seed = (VG_(getpid)() << 9) ^ VG_(getppid)();
421
422 tries = 0;
423 while (True) {
424 if (tries > 10)
425 return -1;
426 VG_(sprintf)( buf, "/tmp/valgrind_%s_%08x",
427 part_of_name, VG_(random)( &seed ));
428 if (0)
429 VG_(printf)("VG_(mkstemp): trying: %s\n", buf);
430
431 sres = VG_(open)(buf,
432 VKI_O_CREAT|VKI_O_RDWR|VKI_O_EXCL|VKI_O_TRUNC,
433 VKI_S_IRUSR|VKI_S_IWUSR);
434 if (sres.isError)
435 continue;
436 /* VG_(safe_fd) doesn't return if it fails. */
sewardj9a66bb92006-10-17 01:38:13 +0000437 fd = VG_(safe_fd)( sres.res );
sewardj45f4e7c2005-09-27 19:20:21 +0000438 if (fullname)
439 VG_(strcpy)( fullname, buf );
440 return fd;
441 }
442 /* NOTREACHED */
443}
444
445
njneb8896b2005-06-04 20:03:55 +0000446/* ---------------------------------------------------------------------
447 Socket-related stuff. This is very Linux-kernel specific.
448 ------------------------------------------------------------------ */
449
450static
451Int parse_inet_addr_and_port ( UChar* str, UInt* ip_addr, UShort* port );
452
453static
454Int my_socket ( Int domain, Int type, Int protocol );
455
456static
sewardj9a66bb92006-10-17 01:38:13 +0000457Int my_connect ( Int sockfd,
458# if defined(VGO_linux)
459 struct vki_sockaddr_in* serv_addr,
460# else
461 void* serv_addr,
462# endif
njneb8896b2005-06-04 20:03:55 +0000463 Int addrlen );
464
toma4a4f412005-11-17 12:01:56 +0000465UInt VG_(htonl) ( UInt x )
njneb8896b2005-06-04 20:03:55 +0000466{
sewardja1c4bfb2005-10-18 02:15:39 +0000467# if defined(VG_BIGENDIAN)
468 return x;
469# else
njneb8896b2005-06-04 20:03:55 +0000470 return
471 (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
472 | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
sewardja1c4bfb2005-10-18 02:15:39 +0000473# endif
njneb8896b2005-06-04 20:03:55 +0000474}
475
toma4a4f412005-11-17 12:01:56 +0000476UInt VG_(ntohl) ( UInt x )
477{
478# if defined(VG_BIGENDIAN)
479 return x;
480# else
481 return
482 (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
483 | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
484# endif
485}
486
487UShort VG_(htons) ( UShort x )
488{
489# if defined(VG_BIGENDIAN)
490 return x;
491# else
492 return
493 (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
494# endif
495}
496
497UShort VG_(ntohs) ( UShort x )
njneb8896b2005-06-04 20:03:55 +0000498{
sewardja1c4bfb2005-10-18 02:15:39 +0000499# if defined(VG_BIGENDIAN)
500 return x;
501# else
njneb8896b2005-06-04 20:03:55 +0000502 return
503 (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
sewardja1c4bfb2005-10-18 02:15:39 +0000504# endif
njneb8896b2005-06-04 20:03:55 +0000505}
506
507
508/* The main function.
509
510 Supplied string contains either an ip address "192.168.0.1" or
511 an ip address and port pair, "192.168.0.1:1500". Parse these,
512 and return:
513 -1 if there is a parse error
514 -2 if no parse error, but specified host:port cannot be opened
515 the relevant file (socket) descriptor, otherwise.
516 is used.
517*/
518Int VG_(connect_via_socket)( UChar* str )
519{
sewardj9a66bb92006-10-17 01:38:13 +0000520#if defined(VGO_aix5)
521 I_die_here;
522#else /* Yay, Linux */
njneb8896b2005-06-04 20:03:55 +0000523 Int sd, res;
524 struct vki_sockaddr_in servAddr;
525 UInt ip = 0;
526 UShort port = VG_CLO_DEFAULT_LOGPORT;
527 Bool ok = parse_inet_addr_and_port(str, &ip, &port);
528 if (!ok)
529 return -1;
530
531 //if (0)
532 // VG_(printf)("ip = %d.%d.%d.%d, port %d\n",
533 // (ip >> 24) & 0xFF, (ip >> 16) & 0xFF,
534 // (ip >> 8) & 0xFF, ip & 0xFF,
535 // (UInt)port );
536
537 servAddr.sin_family = VKI_AF_INET;
toma4a4f412005-11-17 12:01:56 +0000538 servAddr.sin_addr.s_addr = VG_(htonl)(ip);
539 servAddr.sin_port = VG_(htons)(port);
njneb8896b2005-06-04 20:03:55 +0000540
541 /* create socket */
542 sd = my_socket(VKI_AF_INET, VKI_SOCK_STREAM, 0 /* IPPROTO_IP ? */);
543 if (sd < 0) {
sewardja1c4bfb2005-10-18 02:15:39 +0000544 /* this shouldn't happen ... nevertheless */
545 return -2;
njneb8896b2005-06-04 20:03:55 +0000546 }
sewardja1c4bfb2005-10-18 02:15:39 +0000547
njneb8896b2005-06-04 20:03:55 +0000548 /* connect to server */
549 res = my_connect(sd, (struct vki_sockaddr_in *) &servAddr,
550 sizeof(servAddr));
551 if (res < 0) {
sewardja1c4bfb2005-10-18 02:15:39 +0000552 /* connection failed */
553 return -2;
njneb8896b2005-06-04 20:03:55 +0000554 }
555
556 return sd;
sewardj9a66bb92006-10-17 01:38:13 +0000557#endif
njneb8896b2005-06-04 20:03:55 +0000558}
559
560
561/* Let d = one or more digits. Accept either:
562 d.d.d.d or d.d.d.d:d
563*/
sewardj9a66bb92006-10-17 01:38:13 +0000564static Int parse_inet_addr_and_port ( UChar* str, UInt* ip_addr, UShort* port )
njneb8896b2005-06-04 20:03:55 +0000565{
566# define GET_CH ((*str) ? (*str++) : 0)
567 UInt ipa, i, j, c, any;
568 ipa = 0;
569 for (i = 0; i < 4; i++) {
570 j = 0;
571 any = 0;
572 while (1) {
573 c = GET_CH;
574 if (c < '0' || c > '9') break;
575 j = 10 * j + (int)(c - '0');
576 any = 1;
577 }
578 if (any == 0 || j > 255) goto syntaxerr;
579 ipa = (ipa << 8) + j;
580 if (i <= 2 && c != '.') goto syntaxerr;
581 }
582 if (c == 0 || c == ':')
583 *ip_addr = ipa;
584 if (c == 0) goto ok;
585 if (c != ':') goto syntaxerr;
586 j = 0;
587 any = 0;
588 while (1) {
589 c = GET_CH;
590 if (c < '0' || c > '9') break;
591 j = j * 10 + (int)(c - '0');
592 any = 1;
593 if (j > 65535) goto syntaxerr;
594 }
595 if (any == 0 || c != 0) goto syntaxerr;
596 if (j < 1024) goto syntaxerr;
597 *port = (UShort)j;
598 ok:
599 return 1;
600 syntaxerr:
601 return 0;
602# undef GET_CH
603}
604
njneb8896b2005-06-04 20:03:55 +0000605static
606Int my_socket ( Int domain, Int type, Int protocol )
607{
sewardj2c48c7b2005-11-29 13:05:56 +0000608#if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
sewardja8d8e232005-06-07 20:04:56 +0000609 SysRes res;
610 UWord args[3];
njneb8896b2005-06-04 20:03:55 +0000611 args[0] = domain;
612 args[1] = type;
613 args[2] = protocol;
614 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SOCKET, (UWord)&args);
sewardj9a66bb92006-10-17 01:38:13 +0000615 return res.isError ? -1 : res.res;
cerion85665ca2005-06-20 15:51:07 +0000616
617#elif defined(VGP_amd64_linux)
sewardj1e866562005-09-28 19:58:58 +0000618 SysRes res;
619 res = VG_(do_syscall3)(__NR_socket, domain, type, protocol );
sewardj9a66bb92006-10-17 01:38:13 +0000620 return res.isError ? -1 : res.res;
621
622#elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
623 I_die_here;
cerion85665ca2005-06-20 15:51:07 +0000624
cerion85665ca2005-06-20 15:51:07 +0000625#else
626# error Unknown arch
627#endif
njneb8896b2005-06-04 20:03:55 +0000628}
629
630static
sewardj9a66bb92006-10-17 01:38:13 +0000631Int my_connect ( Int sockfd,
632# if defined(VGO_linux)
633 struct vki_sockaddr_in* serv_addr,
634# else
635 void* serv_addr,
636# endif
njneb8896b2005-06-04 20:03:55 +0000637 Int addrlen )
638{
sewardj2c48c7b2005-11-29 13:05:56 +0000639#if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
sewardja8d8e232005-06-07 20:04:56 +0000640 SysRes res;
641 UWord args[3];
njneb8896b2005-06-04 20:03:55 +0000642 args[0] = sockfd;
643 args[1] = (UWord)serv_addr;
644 args[2] = addrlen;
645 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_CONNECT, (UWord)&args);
sewardj9a66bb92006-10-17 01:38:13 +0000646 return res.isError ? -1 : res.res;
cerion85665ca2005-06-20 15:51:07 +0000647
648#elif defined(VGP_amd64_linux)
sewardj1e866562005-09-28 19:58:58 +0000649 SysRes res;
650 res = VG_(do_syscall3)(__NR_connect, sockfd, (UWord)serv_addr, addrlen);
sewardj9a66bb92006-10-17 01:38:13 +0000651 return res.isError ? -1 : res.res;
652
653#elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
654 I_die_here;
cerion85665ca2005-06-20 15:51:07 +0000655
cerion85665ca2005-06-20 15:51:07 +0000656#else
657# error Unknown arch
658#endif
njneb8896b2005-06-04 20:03:55 +0000659}
660
661Int VG_(write_socket)( Int sd, void *msg, Int count )
662{
njneb8896b2005-06-04 20:03:55 +0000663 /* This is actually send(). */
sewardj9a66bb92006-10-17 01:38:13 +0000664 /* For Linux, VKI_MSG_NOSIGNAL is a request not to send SIGPIPE on
665 errors on stream oriented sockets when the other end breaks the
666 connection. The EPIPE error is still returned. */
njneb8896b2005-06-04 20:03:55 +0000667
sewardj2c48c7b2005-11-29 13:05:56 +0000668#if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
sewardja8d8e232005-06-07 20:04:56 +0000669 SysRes res;
670 UWord args[4];
njneb8896b2005-06-04 20:03:55 +0000671 args[0] = sd;
672 args[1] = (UWord)msg;
673 args[2] = count;
sewardj9a66bb92006-10-17 01:38:13 +0000674 args[3] = VKI_MSG_NOSIGNAL;
njneb8896b2005-06-04 20:03:55 +0000675 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SEND, (UWord)&args);
sewardj9a66bb92006-10-17 01:38:13 +0000676 return res.isError ? -1 : res.res;
cerion85665ca2005-06-20 15:51:07 +0000677
678#elif defined(VGP_amd64_linux)
sewardj1e866562005-09-28 19:58:58 +0000679 SysRes res;
sewardj9a66bb92006-10-17 01:38:13 +0000680 res = VG_(do_syscall6)(__NR_sendto, sd, (UWord)msg,
681 count, VKI_MSG_NOSIGNAL, 0,0);
682 return res.isError ? -1 : res.res;
683
684#elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
685 I_die_here;
cerion85665ca2005-06-20 15:51:07 +0000686
cerion85665ca2005-06-20 15:51:07 +0000687#else
688# error Unknown arch
689#endif
njneb8896b2005-06-04 20:03:55 +0000690}
691
692Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen)
693{
sewardj2c48c7b2005-11-29 13:05:56 +0000694#if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
sewardj9a66bb92006-10-17 01:38:13 +0000695 SysRes res;
sewardja8d8e232005-06-07 20:04:56 +0000696 UWord args[3];
njneb8896b2005-06-04 20:03:55 +0000697 args[0] = sd;
698 args[1] = (UWord)name;
699 args[2] = (UWord)namelen;
700 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKNAME, (UWord)&args);
sewardj9a66bb92006-10-17 01:38:13 +0000701 return res.isError ? -1 : res.res;
sewardja5c9e4a2005-06-09 13:21:58 +0000702
cerion85665ca2005-06-20 15:51:07 +0000703#elif defined(VGP_amd64_linux)
sewardj9a66bb92006-10-17 01:38:13 +0000704 SysRes res;
sewardja5c9e4a2005-06-09 13:21:58 +0000705 res = VG_(do_syscall3)( __NR_getsockname,
706 (UWord)sd, (UWord)name, (UWord)namelen );
sewardj9a66bb92006-10-17 01:38:13 +0000707 return res.isError ? -1 : res.res;
708
709#elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
710 I_die_here;
sewardja5c9e4a2005-06-09 13:21:58 +0000711
cerion85665ca2005-06-20 15:51:07 +0000712#else
713# error Unknown arch
714#endif
njneb8896b2005-06-04 20:03:55 +0000715}
716
717Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen)
718{
sewardj2c48c7b2005-11-29 13:05:56 +0000719#if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
sewardj9a66bb92006-10-17 01:38:13 +0000720 SysRes res;
sewardja8d8e232005-06-07 20:04:56 +0000721 UWord args[3];
njneb8896b2005-06-04 20:03:55 +0000722 args[0] = sd;
723 args[1] = (UWord)name;
724 args[2] = (UWord)namelen;
725 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETPEERNAME, (UWord)&args);
sewardj9a66bb92006-10-17 01:38:13 +0000726 return res.isError ? -1 : res.res;
sewardja5c9e4a2005-06-09 13:21:58 +0000727
cerion85665ca2005-06-20 15:51:07 +0000728#elif defined(VGP_amd64_linux)
sewardj9a66bb92006-10-17 01:38:13 +0000729 SysRes res;
sewardja5c9e4a2005-06-09 13:21:58 +0000730 res = VG_(do_syscall3)( __NR_getpeername,
731 (UWord)sd, (UWord)name, (UWord)namelen );
sewardj9a66bb92006-10-17 01:38:13 +0000732 return res.isError ? -1 : res.res;
733
734#elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
735 I_die_here;
sewardja5c9e4a2005-06-09 13:21:58 +0000736
cerion85665ca2005-06-20 15:51:07 +0000737#else
sewardj9a66bb92006-10-17 01:38:13 +0000738# error Unknown arch
cerion85665ca2005-06-20 15:51:07 +0000739#endif
njneb8896b2005-06-04 20:03:55 +0000740}
741
742Int VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval,
743 Int *optlen)
744{
sewardj2c48c7b2005-11-29 13:05:56 +0000745#if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
sewardj9a66bb92006-10-17 01:38:13 +0000746 SysRes res;
sewardja8d8e232005-06-07 20:04:56 +0000747 UWord args[5];
njneb8896b2005-06-04 20:03:55 +0000748 args[0] = sd;
749 args[1] = level;
750 args[2] = optname;
751 args[3] = (UWord)optval;
752 args[4] = (UWord)optlen;
753 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKOPT, (UWord)&args);
sewardj9a66bb92006-10-17 01:38:13 +0000754 return res.isError ? -1 : res.res;
sewardja5c9e4a2005-06-09 13:21:58 +0000755
cerion85665ca2005-06-20 15:51:07 +0000756#elif defined(VGP_amd64_linux)
sewardj9a66bb92006-10-17 01:38:13 +0000757 SysRes res;
sewardja5c9e4a2005-06-09 13:21:58 +0000758 res = VG_(do_syscall5)( __NR_getsockopt,
759 (UWord)sd, (UWord)level, (UWord)optname,
760 (UWord)optval, (UWord)optlen );
sewardj9a66bb92006-10-17 01:38:13 +0000761 return res.isError ? -1 : res.res;
762
763#elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
764 I_die_here;
sewardja5c9e4a2005-06-09 13:21:58 +0000765
cerion85665ca2005-06-20 15:51:07 +0000766#else
767# error Unknown arch
768#endif
njneb8896b2005-06-04 20:03:55 +0000769}
770
771
772
773/*--------------------------------------------------------------------*/
774/*--- end ---*/
775/*--------------------------------------------------------------------*/
776