diff options
author | Corinna Vinschen <vinschen@redhat.com> | 2006-07-06 14:04:32 +0000 |
---|---|---|
committer | Corinna Vinschen <vinschen@redhat.com> | 2006-07-06 14:04:32 +0000 |
commit | 6836437f9c15dad5088da4ecfcd8ca44a56e6d63 (patch) | |
tree | 0783f22039a6c503fdb9d09e38d885b3d0b73808 | |
parent | 9ee064b4bd06b7be50fbc976c46172f83557f084 (diff) | |
download | gdb-6836437f9c15dad5088da4ecfcd8ca44a56e6d63.tar.gz |
* cygwin.din: Export in6addr_any, in6addr_loopback, freeaddrinfo,
gai_strerror, getaddrinfo, getnameinfo.
* fhandler_socket.cc: Include cygwin/in6.h.
(get_inet_addr): Accomodate AF_INET6 usage.
(fhandler_socket::connect): Ditto.
(fhandler_socket::listen): Ditto.
(fhandler_socket::sendto): Ditto.
* net.cc: Include cygwin/in6.h.
(in6addr_any): Define.
(in6addr_loopback): Define.
(cygwin_socket): Accomodate AF_INET6 usage.
(socketpair): Bind socketpairs only to loopback for security.
(inet_pton4): New static function.
(inet_pton6): Ditto.
(cygwin_inet_pton): New AF_INET6 aware inet_pton implementation.
(inet_ntop4): New static function.
(inet_ntop6): Ditto.
(cygwin_inet_ntop): New AF_INET6 aware inet_ntop implementation.
(ga_aistruct): New static function.
(ga_clone): Ditto.
(ga_echeck): Ditto.
(ga_nsearch): Ditto.
(ga_port): Ditto.
(ga_serv): Ditto.
(ga_unix): Ditto.
(gn_ipv46): Ditto.
(ipv4_freeaddrinfo): Ditto.
(ipv4_getaddrinfo): Ditto.
(ipv4_getnameinfo): Ditto.
(gai_errmap_t): New structure holding error code - error string mapping.
(cygwin_gai_strerror): New function implementing gai_strerror.
(w32_to_gai_err): New static function.
(get_ipv6_funcs): Ditto.
(load_ipv6_funcs): Ditto.
(cygwin_freeaddrinfo): New function implementing freeaddrinfo.
(cygwin_getaddrinfo): New function implementing getaddrinfo.
(cygwin_getnameinfo): New function implementing getnameinfo.
* include/netdb.h: Include stdint.h and cygwin/socket.h. Define
data types and macros used by getaddrinfo and friends. Declare
freeaddrinfo, gai_strerror, getaddrinfo and getnameinfo.
* include/cygwin/in.h: Add IPv6 related IPPROTOs. Remove definition
of struct sockaddr_in6. Include cygwin/in6.h instead.
* include/cygwin/in6.h: New header file defining IPv6 releated
data types and macros.
* include/cygwin/socket.h: Enable AF_INET6 and PF_INET6. Add
IPv6 related socket options.
* include/cygwin/version.h: Bump API minor number.
-rw-r--r-- | winsup/cygwin/ChangeLog | 50 | ||||
-rw-r--r-- | winsup/cygwin/cygwin.din | 1628 | ||||
-rw-r--r-- | winsup/cygwin/fhandler_socket.cc | 1694 | ||||
-rw-r--r-- | winsup/cygwin/include/cygwin/in.h | 209 | ||||
-rw-r--r-- | winsup/cygwin/include/cygwin/in6.h | 119 | ||||
-rw-r--r-- | winsup/cygwin/include/cygwin/socket.h | 277 | ||||
-rw-r--r-- | winsup/cygwin/include/cygwin/version.h | 367 | ||||
-rw-r--r-- | winsup/cygwin/include/netdb.h | 227 | ||||
-rw-r--r-- | winsup/cygwin/net.cc | 3629 |
9 files changed, 8200 insertions, 0 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 9ab0c2cb1b7..f4c954db660 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,5 +1,55 @@ 2006-07-06 Corinna Vinschen <corinna@vinschen.de> + * cygwin.din: Export in6addr_any, in6addr_loopback, freeaddrinfo, + gai_strerror, getaddrinfo, getnameinfo. + * fhandler_socket.cc: Include cygwin/in6.h. + (get_inet_addr): Accomodate AF_INET6 usage. + (fhandler_socket::connect): Ditto. + (fhandler_socket::listen): Ditto. + (fhandler_socket::sendto): Ditto. + * net.cc: Include cygwin/in6.h. + (in6addr_any): Define. + (in6addr_loopback): Define. + (cygwin_socket): Accomodate AF_INET6 usage. + (socketpair): Bind socketpairs only to loopback for security. + (inet_pton4): New static function. + (inet_pton6): Ditto. + (cygwin_inet_pton): New AF_INET6 aware inet_pton implementation. + (inet_ntop4): New static function. + (inet_ntop6): Ditto. + (cygwin_inet_ntop): New AF_INET6 aware inet_ntop implementation. + (ga_aistruct): New static function. + (ga_clone): Ditto. + (ga_echeck): Ditto. + (ga_nsearch): Ditto. + (ga_port): Ditto. + (ga_serv): Ditto. + (ga_unix): Ditto. + (gn_ipv46): Ditto. + (ipv4_freeaddrinfo): Ditto. + (ipv4_getaddrinfo): Ditto. + (ipv4_getnameinfo): Ditto. + (gai_errmap_t): New structure holding error code - error string mapping. + (cygwin_gai_strerror): New function implementing gai_strerror. + (w32_to_gai_err): New static function. + (get_ipv6_funcs): Ditto. + (load_ipv6_funcs): Ditto. + (cygwin_freeaddrinfo): New function implementing freeaddrinfo. + (cygwin_getaddrinfo): New function implementing getaddrinfo. + (cygwin_getnameinfo): New function implementing getnameinfo. + * include/netdb.h: Include stdint.h and cygwin/socket.h. Define + data types and macros used by getaddrinfo and friends. Declare + freeaddrinfo, gai_strerror, getaddrinfo and getnameinfo. + * include/cygwin/in.h: Add IPv6 related IPPROTOs. Remove definition + of struct sockaddr_in6. Include cygwin/in6.h instead. + * include/cygwin/in6.h: New header file defining IPv6 releated + data types and macros. + * include/cygwin/socket.h: Enable AF_INET6 and PF_INET6. Add + IPv6 related socket options. + * include/cygwin/version.h: Bump API minor number. + +2006-07-06 Corinna Vinschen <corinna@vinschen.de> + * autoload.cc (DsGetDcNameA): Define. (NetGetAnyDCName): Define. * security.cc: Include dsgetdc.h. diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din new file mode 100644 index 00000000000..7d00b785b41 --- /dev/null +++ b/winsup/cygwin/cygwin.din @@ -0,0 +1,1628 @@ +LIBRARY "cygwin1.dll" BASE=0x61000000 + +EXPORTS +__argc DATA +__argv DATA +_check_for_executable DATA +__check_rhosts_file DATA +_ctype_ DATA +__cygwin_environ DATA +__cygwin_user_data DATA +_daylight DATA +h_errno DATA +_impure_ptr DATA +in6addr_any DATA +in6addr_loopback DATA +__mb_cur_max DATA +optarg DATA +opterr DATA +optind DATA +optopt DATA +optreset DATA +__progname DATA +__rcmd_errstr DATA +reent_data DATA +sys_errlist = _sys_errlist DATA +_sys_errlist DATA +sys_nerr = _sys_nerr DATA +_sys_nerr DATA +_timezone DATA +_tzname DATA +a64l NOSIGFE +abort NOSIGFE +_abort = abort SIGFE +abs NOSIGFE +_abs = abs NOSIGFE +accept = cygwin_accept SIGFE +access SIGFE +_access = access SIGFE +acl SIGFE +_acl = acl SIGFE +_acl32 = acl32 SIGFE +aclcheck NOSIGFE +_aclcheck = aclcheck NOSIGFE +_aclcheck32 = aclcheck32 NOSIGFE +aclfrommode SIGFE +_aclfrommode = aclfrommode SIGFE +_aclfrommode32 = aclfrommode32 SIGFE +aclfrompbits SIGFE +_aclfrompbits = aclfrompbits SIGFE +_aclfrompbits32 = aclfrompbits32 SIGFE +aclfromtext SIGFE +_aclfromtext = aclfromtext SIGFE +_aclfromtext32 = aclfromtext32 SIGFE +aclsort SIGFE +_aclsort = aclsort SIGFE +_aclsort32 = aclsort32 SIGFE +acltomode SIGFE +_acltomode = acltomode SIGFE +_acltomode32 = acltomode32 SIGFE +acltopbits SIGFE +_acltopbits = acltopbits SIGFE +_acltopbits32 = acltopbits32 SIGFE +acltotext SIGFE +_acltotext = acltotext SIGFE +_acltotext32 = acltotext32 SIGFE +acos NOSIGFE +_acos = acos NOSIGFE +acosf NOSIGFE +_acosf = acosf NOSIGFE +acosh NOSIGFE +_acosh = acosh NOSIGFE +acoshf NOSIGFE +_acoshf = acoshf NOSIGFE +alarm SIGFE +_alarm = alarm SIGFE +_alloca NOSIGFE +alphasort NOSIGFE +_alphasort = alphasort NOSIGFE +argz_add SIGFE +__argz_add = argz_add SIGFE +argz_add_sep SIGFE +__argz_add_sep = argz_add_sep SIGFE +argz_append SIGFE +__argz_append = argz_append SIGFE +argz_count NOSIGFE +__argz_count = argz_count NOSIGFE +argz_create SIGFE +__argz_create = argz_create SIGFE +argz_create_sep SIGFE +__argz_create_sep = argz_create_sep SIGFE +argz_delete SIGFE +__argz_delete = argz_delete SIGFE +argz_extract NOSIGFE +__argz_extract = argz_extract NOSIGFE +argz_insert SIGFE +__argz_insert = argz_insert SIGFE +argz_next NOSIGFE +__argz_next = argz_next NOSIGFE +argz_replace SIGFE +__argz_replace = argz_replace SIGFE +argz_stringify NOSIGFE +__argz_stringify = argz_stringify NOSIGFE +asctime SIGFE +_asctime = asctime SIGFE +asctime_r SIGFE +_asctime_r = asctime_r SIGFE +asin NOSIGFE +_asin = asin NOSIGFE +asinf NOSIGFE +_asinf = asinf NOSIGFE +asinh NOSIGFE +_asinh = asinh NOSIGFE +asinhf NOSIGFE +_asinhf = asinhf NOSIGFE +asprintf SIGFE +_asprintf = asprintf SIGFE +asprintf_r = _asprintf_r SIGFE +_asprintf_r SIGFE +__assert SIGFE +__assertfail SIGFE +atan NOSIGFE +_atan = atan NOSIGFE +atan2 NOSIGFE +_atan2 = atan2 NOSIGFE +atan2f NOSIGFE +_atan2f = atan2f NOSIGFE +atanf NOSIGFE +_atanf = atanf NOSIGFE +atanh NOSIGFE +_atanh = atanh NOSIGFE +atanhf NOSIGFE +_atanhf = atanhf NOSIGFE +atexit = cygwin_atexit SIGFE +_atexit = cygwin_atexit SIGFE +atof SIGFE +_atof = atof SIGFE +atoff SIGFE +_atoff = atoff SIGFE +atoi NOSIGFE +_atoi = atoi NOSIGFE +atol NOSIGFE +_atol = atol NOSIGFE +atoll NOSIGFE +basename NOSIGFE +bcmp NOSIGFE +_bcmp = bcmp NOSIGFE +bcopy NOSIGFE +_bcopy = bcopy NOSIGFE +bind = cygwin_bind SIGFE +bsearch NOSIGFE +_bsearch = bsearch NOSIGFE +btowc NOSIGFE +bzero NOSIGFE +_bzero = bzero NOSIGFE +cabs NOSIGFE +_cabs = cabs NOSIGFE +cabsf NOSIGFE +_cabsf = cabsf NOSIGFE +calloc SIGFE +_calloc = calloc SIGFE +cbrt NOSIGFE +_cbrt = cbrt NOSIGFE +cbrtf NOSIGFE +_cbrtf = cbrtf NOSIGFE +ceil NOSIGFE +_ceil = ceil NOSIGFE +ceilf NOSIGFE +_ceilf = ceilf NOSIGFE +cfgetispeed NOSIGFE +cfgetospeed NOSIGFE +cfsetispeed SIGFE +cfsetospeed SIGFE +chdir SIGFE +_chdir = chdir SIGFE +chmod SIGFE +_chmod = chmod SIGFE +chown SIGFE +_chown = chown SIGFE +_chown32 = chown32 SIGFE +chroot SIGFE +_chroot = chroot SIGFE +cleanup_glue NOSIGFE +clearerr SIGFE +_clearerr = clearerr SIGFE +clock SIGFE +_clock = clock SIGFE +clock_getres SIGFE +clock_gettime SIGFE +clock_setres SIGFE +close SIGFE +_close = close SIGFE +closedir SIGFE +_closedir = closedir SIGFE +closelog SIGFE +connect = cygwin_connect SIGFE +copysign NOSIGFE +_copysign = copysign NOSIGFE +copysignf NOSIGFE +_copysignf = copysignf NOSIGFE +cos NOSIGFE +_cos = cos NOSIGFE +cosf NOSIGFE +_cosf = cosf NOSIGFE +cosh NOSIGFE +_cosh = cosh NOSIGFE +coshf NOSIGFE +_coshf = coshf NOSIGFE +creat SIGFE +_creat = creat SIGFE +ctermid SIGFE +ctime SIGFE +_ctime = ctime SIGFE +ctime_r SIGFE +_ctime_r = ctime_r SIGFE +cuserid NOSIGFE +_cuserid = cuserid NOSIGFE +cwait SIGFE +_cwait = cwait SIGFE +cygwin32_attach_handle_to_fd = cygwin_attach_handle_to_fd SIGFE +cygwin32_conv_to_full_posix_path = cygwin_conv_to_full_posix_path SIGFE +cygwin32_conv_to_full_win32_path = cygwin_conv_to_full_win32_path SIGFE +cygwin32_conv_to_posix_path = cygwin_conv_to_posix_path SIGFE +cygwin32_conv_to_win32_path = cygwin_conv_to_win32_path SIGFE +cygwin32_detach_dll = cygwin_detach_dll SIGFE_MAYBE +cygwin32_internal = cygwin_internal SIGFE +cygwin32_posix_path_list_p = cygwin_posix_path_list_p NOSIGFE +cygwin32_posix_to_win32_path_list = cygwin_posix_to_win32_path_list SIGFE +cygwin32_posix_to_win32_path_list_buf_size = cygwin_posix_to_win32_path_list_buf_size SIGFE +cygwin32_split_path = cygwin_split_path NOSIGFE +cygwin32_win32_to_posix_path_list = cygwin_win32_to_posix_path_list SIGFE +cygwin32_win32_to_posix_path_list_buf_size = cygwin_win32_to_posix_path_list_buf_size SIGFE +cygwin32_winpid_to_pid = cygwin_winpid_to_pid SIGFE +cygwin_attach_handle_to_fd SIGFE +cygwin_conv_to_full_posix_path SIGFE +cygwin_conv_to_full_win32_path SIGFE +cygwin_conv_to_posix_path SIGFE +cygwin_conv_to_win32_path SIGFE +cygwin_detach_dll SIGFE_MAYBE +cygwin_dll_init NOSIGFE +cygwin_internal NOSIGFE +cygwin_logon_user SIGFE +cygwin_posix_path_list_p NOSIGFE +cygwin_posix_to_win32_path_list SIGFE +cygwin_posix_to_win32_path_list_buf_size SIGFE +cygwin_set_impersonation_token SIGFE +cygwin_split_path NOSIGFE +cygwin_stackdump SIGFE +cygwin_umount SIGFE +cygwin_win32_to_posix_path_list SIGFE +cygwin_win32_to_posix_path_list_buf_size SIGFE +cygwin_winpid_to_pid SIGFE +daemon SIGFE +difftime NOSIGFE +_difftime = difftime NOSIGFE +dirfd SIGFE +_dirfd = dirfd SIGFE +dirname NOSIGFE +div NOSIGFE +_div = div NOSIGFE +dlclose SIGFE +dlerror NOSIGFE +dlfork NOSIGFE +_dll_crt0@0 NOSIGFE +dll_crt0__FP11per_process NOSIGFE +dll_dllcrt0 NOSIGFE +dll_entry@12 NOSIGFE +dll_noncygwin_dllcrt0 NOSIGFE +dlopen SIGFE +dlsym SIGFE +drand48 NOSIGFE +_drand48 = drand48 NOSIGFE +drem NOSIGFE +_drem = drem NOSIGFE +dremf NOSIGFE +_dremf = dremf NOSIGFE +dup SIGFE +_dup = dup SIGFE +dup2 SIGFE +_dup2 = dup2 SIGFE +ecvt SIGFE +_ecvt = ecvt SIGFE +ecvtbuf SIGFE +_ecvtbuf = ecvtbuf SIGFE +ecvtf SIGFE +_ecvtf = ecvtf SIGFE +endgrent NOSIGFE +_endgrent = endgrent NOSIGFE +endhostent NOSIGFE +endmntent NOSIGFE +_endmntent = endmntent NOSIGFE +endprotoent = cygwin_endprotoent SIGFE +endpwent NOSIGFE +_endpwent = endpwent NOSIGFE +endservent = cygwin_endservent SIGFE +endusershell SIGFE +endutent SIGFE +_endutent = endutent SIGFE +endutxent SIGFE +envz_add SIGFE +__envz_add = envz_add SIGFE +envz_entry NOSIGFE +__envz_entry = envz_entry NOSIGFE +envz_get NOSIGFE +__envz_get = envz_get NOSIGFE +envz_merge SIGFE +__envz_merge = envz_merge SIGFE +envz_remove SIGFE +__envz_remove = envz_remove SIGFE +envz_strip SIGFE +__envz_strip = envz_strip SIGFE +__eprintf SIGFE +erand48 NOSIGFE +_erand48 = erand48 NOSIGFE +erf NOSIGFE +_erf = erf NOSIGFE +erfc NOSIGFE +_erfc = erfc NOSIGFE +erfcf NOSIGFE +_erfcf = erfcf NOSIGFE +erff NOSIGFE +_erff = erff NOSIGFE +err SIGFE +__errno NOSIGFE +errx SIGFE +execl SIGFE +_execl = execl SIGFE +execle SIGFE +_execle = execle SIGFE +execlp SIGFE +_execlp = execlp SIGFE +execv SIGFE +_execv = execv SIGFE +execve SIGFE +_execve = execve SIGFE +execvp SIGFE +_execvp = execvp SIGFE +exit = cygwin_exit SIGFE +_exit SIGFE +exp NOSIGFE +_exp = exp NOSIGFE +exp2 NOSIGFE +exp2f NOSIGFE +expf NOSIGFE +_expf = expf NOSIGFE +expm1 NOSIGFE +_expm1 = expm1 NOSIGFE +expm1f NOSIGFE +_expm1f = expm1f NOSIGFE +_f_atan2 NOSIGFE +__f_atan2 = _f_atan2 NOSIGFE +_f_atan2f NOSIGFE +__f_atan2f = _f_atan2f NOSIGFE +_f_exp NOSIGFE +__f_exp = _f_exp NOSIGFE +_f_expf NOSIGFE +__f_expf = _f_expf NOSIGFE +_f_frexp NOSIGFE +__f_frexp = _f_frexp NOSIGFE +_f_frexpf NOSIGFE +__f_frexpf = _f_frexpf NOSIGFE +_f_ldexp NOSIGFE +__f_ldexp = _f_ldexp NOSIGFE +_f_ldexpf NOSIGFE +__f_ldexpf = _f_ldexpf NOSIGFE +_f_log NOSIGFE +__f_log = _f_log NOSIGFE +_f_log10 NOSIGFE +__f_log10 = _f_log10 NOSIGFE +_f_log10f NOSIGFE +__f_log10f = _f_log10f NOSIGFE +_f_logf NOSIGFE +__f_logf = _f_logf NOSIGFE +_f_pow NOSIGFE +__f_pow = _f_pow NOSIGFE +_f_powf NOSIGFE +__f_powf = _f_powf NOSIGFE +_f_tan NOSIGFE +__f_tan = _f_tan NOSIGFE +_f_tanf NOSIGFE +__f_tanf = _f_tanf NOSIGFE +fabs NOSIGFE +_fabs = fabs NOSIGFE +fabsf NOSIGFE +_fabsf = fabsf NOSIGFE +facl SIGFE +_facl = facl SIGFE +_facl32 = facl32 SIGFE +fchdir SIGFE +_fchdir = fchdir SIGFE +fchmod SIGFE +_fchmod = fchmod SIGFE +fchown SIGFE +_fchown = fchown SIGFE +_fchown32 = fchown32 SIGFE +fclose SIGFE +_fclose = fclose SIGFE +fcloseall SIGFE +_fcloseall = fcloseall SIGFE +fcloseall_r = _fcloseall_r SIGFE +_fcloseall_r SIGFE +fcntl SIGFE +_fcntl = fcntl SIGFE +_fcntl64 = fcntl64 SIGFE +fcvt SIGFE +_fcvt = fcvt SIGFE +fcvtbuf SIGFE +_fcvtbuf = fcvtbuf SIGFE +fcvtf SIGFE +_fcvtf = fcvtf SIGFE +fdatasync SIGFE +fdim NOSIGFE +fdimf NOSIGFE +fdopen SIGFE +_fdopen = fdopen SIGFE +_fdopen64 = fdopen64 SIGFE +feof SIGFE +_feof = feof SIGFE +ferror SIGFE +_ferror = ferror SIGFE +fflush SIGFE +_fflush = fflush SIGFE +ffs NOSIGFE +_ffs = ffs NOSIGFE +fgetc SIGFE +_fgetc = fgetc SIGFE +fgetpos SIGFE +_fgetpos = fgetpos SIGFE +_fgetpos64 = fgetpos64 SIGFE +fgets SIGFE +_fgets = fgets SIGFE +fileno SIGFE +_fileno = fileno SIGFE +finite NOSIGFE +_finite = finite NOSIGFE +finitef NOSIGFE +_finitef = finitef NOSIGFE +fiprintf SIGFE +_fiprintf = fiprintf SIGFE +flock SIGFE +flockfile SIGFE +floor NOSIGFE +_floor = floor NOSIGFE +floorf NOSIGFE +_floorf = floorf NOSIGFE +fma NOSIGFE +fmaf NOSIGFE +fmax NOSIGFE +fmaxf NOSIGFE +fmin NOSIGFE +fminf NOSIGFE +fmod NOSIGFE +_fmod = fmod NOSIGFE +fmodf NOSIGFE +_fmodf = fmodf NOSIGFE +fnmatch NOSIGFE +_fnmatch = fnmatch NOSIGFE +fopen SIGFE +_fopen = fopen SIGFE +_fopen64 = fopen64 SIGFE +fork SIGFE +_fork = fork SIGFE +forkpty SIGFE +fpathconf SIGFE +__fpclassifyd NOSIGFE +__fpclassifyf NOSIGFE +fprintf SIGFE +_fprintf = fprintf SIGFE +fputc SIGFE +_fputc = fputc SIGFE +fputs SIGFE +_fputs = fputs SIGFE +fread SIGFE +_fread = fread SIGFE +free SIGFE +_free = free SIGFE +freeaddrinfo = cygwin_freeaddrinfo SIGFE +freopen SIGFE +_freopen = freopen SIGFE +_freopen64 = freopen64 SIGFE +frexp NOSIGFE +_frexp = frexp NOSIGFE +frexpf NOSIGFE +_frexpf = frexpf NOSIGFE +fscanf SIGFE +_fscanf = fscanf SIGFE +fscanf_r = _fscanf_r SIGFE +_fscanf_r SIGFE +fseek SIGFE +_fseek = fseek SIGFE +fseeko SIGFE +_fseeko = fseeko SIGFE +_fseeko64 = fseeko64 SIGFE +fsetpos SIGFE +_fsetpos = fsetpos SIGFE +_fsetpos64 = fsetpos64 SIGFE +fstat SIGFE +_fstat = fstat SIGFE +_fstat64 = fstat64 SIGFE +fstatfs SIGFE +_fstatfs = fstatfs SIGFE +fstatvfs SIGFE +fsync SIGFE +_fsync = fsync SIGFE +ftell SIGFE +_ftell = ftell SIGFE +ftello SIGFE +_ftello = ftello SIGFE +_ftello64 = ftello64 SIGFE +ftime SIGFE +_ftime = ftime SIGFE +ftok SIGFE +_ftok = ftok SIGFE +ftruncate SIGFE +_ftruncate = ftruncate SIGFE +_ftruncate64 = ftruncate64 SIGFE +ftrylockfile SIGFE +fts_children SIGFE +fts_close SIGFE +fts_get_clientptr NOSIGFE +fts_get_stream NOSIGFE +fts_open SIGFE +fts_read SIGFE +fts_set NOSIGFE +fts_set_clientptr NOSIGFE +ftw SIGFE +funlockfile SIGFE +futimes SIGFE +fwrite SIGFE +_fwrite = fwrite SIGFE +gai_strerror = cygwin_gai_strerror NOSIGFE +gamma NOSIGFE +_gamma = gamma NOSIGFE +gamma_r NOSIGFE +_gamma_r = gamma_r NOSIGFE +gammaf NOSIGFE +_gammaf = gammaf NOSIGFE +gammaf_r NOSIGFE +_gammaf_r = gammaf_r NOSIGFE +gcvt SIGFE +_gcvt = gcvt SIGFE +gcvtf SIGFE +_gcvtf = gcvtf SIGFE +get_osfhandle SIGFE +_get_osfhandle = get_osfhandle SIGFE +getaddrinfo = cygwin_getaddrinfo SIGFE +getc SIGFE +_getc = getc SIGFE +getc_unlocked SIGFE +_getc_unlocked = getc_unlocked SIGFE +getchar SIGFE +_getchar = getchar SIGFE +getchar_unlocked SIGFE +_getchar_unlocked = getchar_unlocked SIGFE +getcwd SIGFE +_getcwd = getcwd SIGFE +getdelim = __getdelim SIGFE +__getdelim SIGFE +getdomainname SIGFE +_getdomainname = getdomainname SIGFE +getdtablesize NOSIGFE +_getdtablesize = getdtablesize NOSIGFE +getegid NOSIGFE +_getegid = getegid NOSIGFE +_getegid32 = getegid32 NOSIGFE +getenv NOSIGFE +_getenv = getenv NOSIGFE +geteuid NOSIGFE +_geteuid = geteuid NOSIGFE +_geteuid32 = geteuid32 NOSIGFE +getgid NOSIGFE +_getgid = getgid NOSIGFE +_getgid32 = getgid32 NOSIGFE +getgrent SIGFE +_getgrent = getgrent SIGFE +_getgrent32 = getgrent32 SIGFE +getgrgid SIGFE +_getgrgid = getgrgid SIGFE +_getgrgid32 = getgrgid32 SIGFE +getgrgid_r SIGFE +getgrnam SIGFE +_getgrnam = getgrnam SIGFE +_getgrnam32 = getgrnam32 SIGFE +getgrnam_r SIGFE +getgroups SIGFE +_getgroups = getgroups SIGFE +_getgroups32 = getgroups32 SIGFE +gethostbyaddr = cygwin_gethostbyaddr SIGFE +gethostbyname = cygwin_gethostbyname SIGFE +gethostid SIGFE +gethostname = cygwin_gethostname SIGFE +_gethostname = cygwin_gethostname SIGFE +getitimer SIGFE +getline = __getline SIGFE +__getline SIGFE +getlogin NOSIGFE +_getlogin = getlogin NOSIGFE +getlogin_r NOSIGFE +getmntent SIGFE +_getmntent = getmntent SIGFE +getmode SIGFE +_getmode = getmode SIGFE +getnameinfo = cygwin_getnameinfo SIGFE +getopt SIGFE +getopt_long SIGFE +getopt_long_only SIGFE +getpagesize SIGFE +_getpagesize = getpagesize SIGFE +getpass SIGFE +_getpass = getpass SIGFE +getpeereid SIGFE +getpeername = cygwin_getpeername SIGFE +getpgid SIGFE +getpgrp SIGFE +_getpgrp = getpgrp SIGFE +getpid NOSIGFE +_getpid = getpid NOSIGFE +getppid NOSIGFE +_getppid = getppid NOSIGFE +getpriority SIGFE +getprogname NOSIGFE +getprotobyname = cygwin_getprotobyname SIGFE +getprotobynumber = cygwin_getprotobynumber SIGFE +getprotoent = cygwin_getprotoent SIGFE +getpwduid NOSIGFE +_getpwduid = getpwduid NOSIGFE +getpwent SIGFE +_getpwent = getpwent SIGFE +getpwnam SIGFE +_getpwnam = getpwnam SIGFE +getpwnam_r SIGFE +getpwuid SIGFE +_getpwuid = getpwuid SIGFE +_getpwuid32 = getpwuid32 SIGFE +getpwuid_r SIGFE +_getpwuid_r32 = getpwuid_r32 SIGFE +__getreent NOSIGFE +getrlimit SIGFE +_getrlimit = getrlimit SIGFE +getrusage SIGFE +_getrusage = getrusage SIGFE +gets SIGFE +_gets = gets SIGFE +getservbyname = cygwin_getservbyname SIGFE +getservbyport = cygwin_getservbyport SIGFE +getservent = cygwin_getservent SIGFE +getsid SIGFE +getsockname = cygwin_getsockname SIGFE +getsockopt = cygwin_getsockopt SIGFE +getsubopt NOSIGFE +gettimeofday SIGFE +_gettimeofday = gettimeofday SIGFE +getuid NOSIGFE +_getuid = getuid NOSIGFE +_getuid32 = getuid32 NOSIGFE +getusershell SIGFE +getutent SIGFE +_getutent = getutent SIGFE +getutid SIGFE +_getutid = getutid SIGFE +getutline SIGFE +_getutline = getutline SIGFE +getutxent SIGFE +getutxid SIGFE +getutxline SIGFE +getw SIGFE +_getw = getw SIGFE +getwd SIGFE +_getwd = getwd SIGFE +glob SIGFE +_glob = glob SIGFE +globfree SIGFE +_globfree = globfree SIGFE +gmtime SIGFE +_gmtime = gmtime SIGFE +gmtime_r SIGFE +_gmtime_r = gmtime_r SIGFE +grantpt NOSIGFE +hcreate SIGFE +hcreate_r SIGFE +hdestroy SIGFE +hdestroy_r SIGFE +herror = cygwin_herror SIGFE +hsearch SIGFE +hsearch_r SIGFE +hstrerror = cygwin_hstrerror NOSIGFE +htonl NOSIGFE +_htonl = htonl NOSIGFE +htons NOSIGFE +_htons = htons NOSIGFE +hypot NOSIGFE +_hypot = hypot NOSIGFE +hypotf NOSIGFE +_hypotf = hypotf NOSIGFE +ilogb NOSIGFE +_ilogb = ilogb NOSIGFE +ilogbf NOSIGFE +_ilogbf = ilogbf NOSIGFE +imaxabs = llabs NOSIGFE +imaxdiv = lldiv NOSIGFE +index NOSIGFE +_index = index NOSIGFE +inet_addr = cygwin_inet_addr SIGFE +inet_aton = cygwin_inet_aton SIGFE +inet_makeaddr NOSIGFE +inet_netof NOSIGFE +inet_network = cygwin_inet_network SIGFE +inet_ntoa = cygwin_inet_ntoa SIGFE +inet_ntop = cygwin_inet_ntop SIGFE +inet_pton = cygwin_inet_pton SIGFE +infinity NOSIGFE +_infinity = infinity NOSIGFE +__infinity NOSIGFE +infinityf NOSIGFE +_infinityf = infinityf NOSIGFE +initgroups SIGFE +_initgroups32 = initgroups32 SIGFE +initstate NOSIGFE +ioctl SIGFE +_ioctl = ioctl SIGFE +iprintf SIGFE +_iprintf = iprintf SIGFE +iruserok SIGFE +isalnum NOSIGFE +_isalnum = isalnum NOSIGFE +isalpha NOSIGFE +_isalpha = isalpha NOSIGFE +isascii NOSIGFE +_isascii = isascii NOSIGFE +isatty SIGFE +_isatty = isatty SIGFE +isblank NOSIGFE +iscntrl NOSIGFE +_iscntrl = iscntrl NOSIGFE +isdigit NOSIGFE +_isdigit = isdigit NOSIGFE +isgraph NOSIGFE +_isgraph = isgraph NOSIGFE +isinf NOSIGFE +_isinf = isinf NOSIGFE +__isinfd NOSIGFE +isinff NOSIGFE +_isinff = isinff NOSIGFE +__isinff NOSIGFE +islower NOSIGFE +_islower = islower NOSIGFE +isnan NOSIGFE +_isnan = isnan NOSIGFE +__isnand NOSIGFE +isnanf NOSIGFE +_isnanf = isnanf NOSIGFE +__isnanf NOSIGFE +isprint NOSIGFE +_isprint = isprint NOSIGFE +ispunct NOSIGFE +_ispunct = ispunct NOSIGFE +isspace NOSIGFE +_isspace = isspace NOSIGFE +isupper NOSIGFE +_isupper = isupper NOSIGFE +iswalnum NOSIGFE +iswalpha NOSIGFE +iswblank NOSIGFE +iswcntrl NOSIGFE +iswctype NOSIGFE +iswdigit NOSIGFE +iswgraph NOSIGFE +iswlower NOSIGFE +iswprint NOSIGFE +iswpunct NOSIGFE +iswspace NOSIGFE +iswupper NOSIGFE +iswxdigit NOSIGFE +isxdigit NOSIGFE +_isxdigit = isxdigit NOSIGFE +j0 NOSIGFE +_j0 = j0 NOSIGFE +j0f NOSIGFE +_j0f = j0f NOSIGFE +j1 NOSIGFE +_j1 = j1 NOSIGFE +j1f NOSIGFE +_j1f = j1f NOSIGFE +jn NOSIGFE +_jn = jn NOSIGFE +jnf NOSIGFE +_jnf = jnf NOSIGFE +jrand48 NOSIGFE +_jrand48 = jrand48 NOSIGFE +kill SIGFE +_kill = kill SIGFE +killpg SIGFE +l64a NOSIGFE +labs NOSIGFE +_labs = labs NOSIGFE +lacl SIGFE +_lacl = lacl SIGFE +lchown SIGFE +_lchown = lchown SIGFE +_lchown32 = lchown32 SIGFE +lcong48 NOSIGFE +_lcong48 = lcong48 NOSIGFE +ldexp NOSIGFE +_ldexp = ldexp NOSIGFE +ldexpf NOSIGFE +_ldexpf = ldexpf NOSIGFE +ldiv NOSIGFE +_ldiv = ldiv NOSIGFE +lfind NOSIGFE +lgamma NOSIGFE +_lgamma = lgamma NOSIGFE +lgamma_r NOSIGFE +_lgamma_r = lgamma_r NOSIGFE +lgammaf NOSIGFE +_lgammaf = lgammaf NOSIGFE +lgammaf_r NOSIGFE +_lgammaf_r = lgammaf_r NOSIGFE +link SIGFE +_link = link SIGFE +listen = cygwin_listen SIGFE +llabs NOSIGFE +lldiv NOSIGFE +localeconv NOSIGFE +_localeconv = localeconv NOSIGFE +localtime SIGFE +_localtime = localtime SIGFE +localtime_r SIGFE +_localtime_r = localtime_r SIGFE +log NOSIGFE +_log = log NOSIGFE +log10 NOSIGFE +_log10 = log10 NOSIGFE +log10f NOSIGFE +_log10f = log10f NOSIGFE +log1p NOSIGFE +_log1p = log1p NOSIGFE +log1pf NOSIGFE +_log1pf = log1pf NOSIGFE +logb NOSIGFE +_logb = logb NOSIGFE +logbf NOSIGFE +_logbf = logbf NOSIGFE +logf NOSIGFE +_logf = logf NOSIGFE +login SIGFE +login_tty SIGFE +logout SIGFE +logwtmp SIGFE +longjmp NOSIGFE +_longjmp = longjmp NOSIGFE +lrand48 NOSIGFE +_lrand48 = lrand48 NOSIGFE +lrint NOSIGFE +lrintf NOSIGFE +lround NOSIGFE +lroundf NOSIGFE +lsearch NOSIGFE +lseek SIGFE +_lseek = lseek SIGFE +_lseek64 = lseek64 SIGFE +lstat SIGFE +_lstat = lstat SIGFE +_lstat64 = lstat64 SIGFE +lutimes SIGFE +__main NOSIGFE +mallinfo SIGFE +malloc SIGFE +_malloc = malloc SIGFE +malloc_stats SIGFE +malloc_trim SIGFE +malloc_usable_size SIGFE +mallopt SIGFE +matherr NOSIGFE +_matherr = matherr NOSIGFE +mblen NOSIGFE +_mblen = mblen NOSIGFE +mbrlen NOSIGFE +mbrtowc NOSIGFE +mbsinit NOSIGFE +mbsrtowcs NOSIGFE +mbstowcs NOSIGFE +_mbstowcs = mbstowcs NOSIGFE +mbtowc NOSIGFE +_mbtowc = mbtowc NOSIGFE +memalign SIGFE +memccpy NOSIGFE +_memccpy = memccpy NOSIGFE +memchr NOSIGFE +_memchr = memchr NOSIGFE +memcmp NOSIGFE +_memcmp = memcmp NOSIGFE +memcpy NOSIGFE +_memcpy = memcpy NOSIGFE +memmem NOSIGFE +memmove NOSIGFE +_memmove = memmove NOSIGFE +mempcpy NOSIGFE +__mempcpy = mempcpy NOSIGFE +memset NOSIGFE +_memset = memset NOSIGFE +mkdir SIGFE +_mkdir = mkdir SIGFE +mkdtemp SIGFE +mkfifo SIGFE +mknod SIGFE +_mknod = mknod SIGFE +_mknod32 = mknod32 SIGFE +mkstemp SIGFE +_mkstemp = mkstemp SIGFE +mktemp SIGFE +_mktemp = mktemp SIGFE +mktime SIGFE +_mktime = mktime SIGFE +mlock SIGFE +mmap SIGFE +_mmap64 = mmap64 SIGFE +modf NOSIGFE +_modf = modf NOSIGFE +modff NOSIGFE +_modff = modff NOSIGFE +mount SIGFE +_mount = mount SIGFE +mprotect SIGFE +mrand48 NOSIGFE +msgctl SIGFE +msgget SIGFE +msgrcv SIGFE +msgsnd SIGFE +msync SIGFE +munlock SIGFE +munmap SIGFE +nan NOSIGFE +_nan = nan NOSIGFE +nanf NOSIGFE +_nanf = nanf NOSIGFE +nanosleep SIGFE +_nanosleep = nanosleep SIGFE +nearbyint NOSIGFE +nearbyintf NOSIGFE +nextafter NOSIGFE +_nextafter = nextafter NOSIGFE +nextafterf NOSIGFE +_nextafterf = nextafterf NOSIGFE +nftw SIGFE +nice SIGFE +_nice = nice SIGFE +nl_langinfo SIGFE +_nl_langinfo = nl_langinfo SIGFE +nrand48 NOSIGFE +_nrand48 = nrand48 NOSIGFE +ntohl NOSIGFE +_ntohl = ntohl NOSIGFE +ntohs NOSIGFE +_ntohs = ntohs NOSIGFE +on_exit SIGFE +open SIGFE +_open = open SIGFE +_open64 +opendir SIGFE +__opendir_with_d_ino SIGFE +openlog SIGFE +_openlog = openlog SIGFE +openpty SIGFE +pathconf SIGFE +_pathconf = pathconf SIGFE +pause SIGFE +pclose SIGFE +_pclose = pclose SIGFE +perror SIGFE +_perror = perror SIGFE +pipe SIGFE +_pipe SIGFE +poll SIGFE +_poll = poll SIGFE +popen SIGFE +_popen = popen SIGFE +posix_regcomp SIGFE +posix_regerror SIGFE +posix_regexec SIGFE +posix_regfree SIGFE +pow NOSIGFE +_pow = pow NOSIGFE +powf NOSIGFE +_powf = powf NOSIGFE +pread SIGFE +printf SIGFE +_printf = printf SIGFE +pselect SIGFE +pthread_atfork SIGFE +pthread_attr_destroy SIGFE +pthread_attr_getdetachstate SIGFE +pthread_attr_getinheritsched SIGFE +pthread_attr_getschedparam SIGFE +pthread_attr_getschedpolicy SIGFE +pthread_attr_getscope SIGFE +pthread_attr_getstacksize SIGFE +pthread_attr_init SIGFE +pthread_attr_setdetachstate SIGFE +pthread_attr_setinheritsched SIGFE +pthread_attr_setschedparam SIGFE +pthread_attr_setschedpolicy SIGFE +pthread_attr_setscope SIGFE +pthread_attr_setstacksize SIGFE +pthread_cancel SIGFE +_pthread_cleanup_pop SIGFE +_pthread_cleanup_push SIGFE +pthread_cond_broadcast SIGFE +pthread_cond_destroy SIGFE +pthread_cond_init SIGFE +pthread_cond_signal SIGFE +pthread_cond_timedwait SIGFE +pthread_cond_wait SIGFE +pthread_condattr_destroy SIGFE +pthread_condattr_getpshared SIGFE +pthread_condattr_init SIGFE +pthread_condattr_setpshared SIGFE +pthread_continue SIGFE +pthread_create SIGFE +pthread_detach SIGFE +pthread_equal SIGFE +pthread_exit SIGFE +pthread_getconcurrency SIGFE +pthread_getschedparam SIGFE +pthread_getsequence_np SIGFE +pthread_getspecific SIGFE +pthread_join SIGFE +pthread_key_create SIGFE +pthread_key_delete SIGFE +pthread_kill SIGFE +pthread_mutex_destroy SIGFE +pthread_mutex_getprioceiling SIGFE +pthread_mutex_init SIGFE +pthread_mutex_lock SIGFE +pthread_mutex_setprioceiling SIGFE +pthread_mutex_trylock SIGFE +pthread_mutex_unlock SIGFE +pthread_mutexattr_destroy SIGFE +pthread_mutexattr_getprioceiling SIGFE +pthread_mutexattr_getprotocol SIGFE +pthread_mutexattr_getpshared SIGFE +pthread_mutexattr_gettype SIGFE +pthread_mutexattr_init SIGFE +pthread_mutexattr_setprioceiling SIGFE +pthread_mutexattr_setprotocol SIGFE +pthread_mutexattr_setpshared SIGFE +pthread_mutexattr_settype SIGFE +pthread_once SIGFE +pthread_rwlock_destroy SIGFE +pthread_rwlock_init SIGFE +pthread_rwlock_rdlock SIGFE +pthread_rwlock_tryrdlock SIGFE +pthread_rwlock_trywrlock SIGFE +pthread_rwlock_unlock SIGFE +pthread_rwlock_wrlock SIGFE +pthread_rwlockattr_destroy SIGFE +pthread_rwlockattr_getpshared SIGFE +pthread_rwlockattr_init SIGFE +pthread_rwlockattr_setpshared SIGFE +pthread_self SIGFE +pthread_setcancelstate SIGFE +pthread_setcanceltype SIGFE +pthread_setconcurrency SIGFE +pthread_setschedparam SIGFE +pthread_setspecific SIGFE +pthread_sigmask SIGFE +pthread_suspend SIGFE +pthread_testcancel SIGFE +ptsname SIGFE +putc SIGFE +_putc = putc SIGFE +putc_unlocked SIGFE +_putc_unlocked = putc_unlocked SIGFE +putchar SIGFE +_putchar = putchar SIGFE +putchar_unlocked SIGFE +_putchar_unlocked = putchar_unlocked SIGFE +putenv SIGFE +_putenv = putenv SIGFE +puts SIGFE +_puts = puts SIGFE +pututline SIGFE +_pututline = pututline SIGFE +pututxline SIGFE +putw SIGFE +_putw = putw SIGFE +pwrite SIGFE +qsort NOSIGFE +_qsort = qsort NOSIGFE +raise SIGFE +_raise = raise SIGFE +rand NOSIGFE +_rand = rand NOSIGFE +rand_r NOSIGFE +random NOSIGFE +rcmd = cygwin_rcmd SIGFE +read SIGFE +_read = read SIGFE +readdir SIGFE +_readdir = readdir SIGFE +readdir_r SIGFE +readlink SIGFE +_readlink = readlink SIGFE +readv SIGFE +_readv = readv SIGFE +realloc SIGFE +_realloc = realloc SIGFE +realpath SIGFE +recv = cygwin_recv SIGFE +recvfrom = cygwin_recvfrom SIGFE +recvmsg = cygwin_recvmsg SIGFE +remainder NOSIGFE +_remainder = remainder NOSIGFE +remainderf NOSIGFE +_remainderf = remainderf NOSIGFE +remove SIGFE +_remove = remove SIGFE +remquo NOSIGFE +remquof NOSIGFE +rename SIGFE +_rename = rename SIGFE +revoke SIGFE +rewind SIGFE +_rewind = rewind SIGFE +rewinddir SIGFE +_rewinddir = rewinddir SIGFE +rexec = cygwin_rexec SIGFE +rindex NOSIGFE +_rindex = rindex NOSIGFE +rint NOSIGFE +_rint = rint NOSIGFE +rintf NOSIGFE +_rintf = rintf NOSIGFE +rmdir SIGFE +_rmdir = rmdir SIGFE +round NOSIGFE +roundf NOSIGFE +rresvport = cygwin_rresvport SIGFE +ruserok SIGFE +sbrk SIGFE +_sbrk = sbrk SIGFE +scalb NOSIGFE +_scalb = scalb NOSIGFE +scalbf NOSIGFE +_scalbf = scalbf NOSIGFE +scalbln NOSIGFE +scalblnf NOSIGFE +scalbn NOSIGFE +_scalbn = scalbn NOSIGFE +scalbnf NOSIGFE +_scalbnf = scalbnf NOSIGFE +scandir SIGFE +_scandir = scandir SIGFE +scanf SIGFE +_scanf = scanf SIGFE +scanf_r = _scanf_r SIGFE +_scanf_r SIGFE +sched_get_priority_max SIGFE +sched_get_priority_min SIGFE +sched_getparam SIGFE +sched_getscheduler NOSIGFE +sched_rr_get_interval SIGFE +sched_setparam SIGFE +sched_setscheduler SIGFE +sched_yield SIGFE +seed48 NOSIGFE +_seed48 = seed48 NOSIGFE +seekdir SIGFE +_seekdir = seekdir SIGFE +_seekdir64 = seekdir64 SIGFE +select = cygwin_select SIGFE +_select = cygwin_select SIGFE +sem_close SIGFE +sem_destroy SIGFE +sem_getvalue SIGFE +sem_init SIGFE +sem_open SIGFE +sem_post SIGFE +sem_timedwait SIGFE +sem_trywait SIGFE +sem_wait SIGFE +semctl SIGFE +semget SIGFE +semop SIGFE +send = cygwin_send SIGFE +sendmsg = cygwin_sendmsg SIGFE +sendto = cygwin_sendto SIGFE +setbuf SIGFE +_setbuf = setbuf SIGFE +setbuffer SIGFE +setdtablesize SIGFE +_setdtablesize = setdtablesize SIGFE +setegid SIGFE +_setegid = setegid SIGFE +_setegid32 = setegid32 SIGFE +setenv SIGFE +_setenv = setenv SIGFE +seteuid SIGFE +_seteuid = seteuid SIGFE +_seteuid32 = seteuid32 SIGFE +setgid SIGFE +_setgid = setgid SIGFE +_setgid32 = setgid32 SIGFE +setgrent NOSIGFE +_setgrent = setgrent NOSIGFE +setgroups SIGFE +_setgroups = setgroups SIGFE +_setgroups32 = setgroups32 SIGFE +sethostent NOSIGFE +setitimer SIGFE +setjmp NOSIGFE +_setjmp = setjmp NOSIGFE +setlinebuf SIGFE +setlocale NOSIGFE +_setlocale = setlocale NOSIGFE +setlogmask NOSIGFE +setmntent SIGFE +_setmntent = setmntent SIGFE +setmode = cygwin_setmode SIGFE +_setmode = cygwin_setmode SIGFE +setpassent NOSIGFE +_setpassent = setpassent NOSIGFE +setpgid SIGFE +_setpgid = setpgid SIGFE +setpgrp SIGFE +_setpgrp = setpgrp SIGFE +setpriority SIGFE +setprogname NOSIGFE +setprotoent = cygwin_setprotoent SIGFE +setpwent NOSIGFE +_setpwent = setpwent NOSIGFE +setregid SIGFE +_setregid = setregid SIGFE +setregid32 SIGFE +_setregid32 = setregid32 SIGFE +setreuid SIGFE +_setreuid = setreuid SIGFE +setreuid32 SIGFE +_setreuid32 = setreuid32 SIGFE +setrlimit SIGFE +_setrlimit = setrlimit SIGFE +setservent = cygwin_setservent SIGFE +setsid SIGFE +_setsid = setsid SIGFE +setsockopt = cygwin_setsockopt SIGFE +setstate NOSIGFE +settimeofday SIGFE +_settimeofday = settimeofday SIGFE +setuid SIGFE +_setuid = setuid SIGFE +_setuid32 = setuid32 SIGFE +setusershell SIGFE +setutent SIGFE +_setutent = setutent SIGFE +setutxent SIGFE +setvbuf SIGFE +_setvbuf = setvbuf SIGFE +sexecl = sexecve_is_bad SIGFE +sexecle = sexecve_is_bad SIGFE +sexeclp = sexecve_is_bad SIGFE +sexeclpe = sexecve_is_bad SIGFE +sexecp = sexecve_is_bad SIGFE +sexecv = sexecve_is_bad SIGFE +sexecve = sexecve_is_bad SIGFE +sexecvpe = sexecve_is_bad SIGFE +shmat SIGFE +shmctl SIGFE +shmdt SIGFE +shmget SIGFE +shutdown = cygwin_shutdown SIGFE +sigaction SIGFE +sigaddset SIGFE +sigdelset SIGFE +sigemptyset NOSIGFE +sigfillset NOSIGFE +sighold SIGFE +sigignore SIGFE +siginterrupt SIGFE +sigismember SIGFE +signal SIGFE +__signbitd NOSIGFE +__signbitf NOSIGFE +__signgam NOSIGFE +significand NOSIGFE +significandf NOSIGFE +sigpause SIGFE +sigpending SIGFE +sigprocmask SIGFE +sigqueue SIGFE +sigrelse SIGFE +sigset SIGFE +sigsuspend SIGFE +sigwait SIGFE +sigwaitinfo SIGFE +sin NOSIGFE +_sin = sin NOSIGFE +sincos NOSIGFE +sincosf NOSIGFE +sinf NOSIGFE +_sinf = sinf NOSIGFE +sinh NOSIGFE +_sinh = sinh NOSIGFE +sinhf NOSIGFE +_sinhf = sinhf NOSIGFE +siprintf SIGFE +_siprintf = siprintf SIGFE +sleep SIGFE +_sleep = sleep SIGFE +snprintf SIGFE +_snprintf = snprintf SIGFE +socket = cygwin_socket SIGFE +socketpair SIGFE +spawnl SIGFE +_spawnl = spawnl SIGFE +spawnle SIGFE +_spawnle = spawnle SIGFE +spawnlp SIGFE +_spawnlp = spawnlp SIGFE +spawnlpe SIGFE +_spawnlpe = spawnlpe SIGFE +spawnv SIGFE +_spawnv = spawnv SIGFE +spawnve SIGFE +_spawnve = spawnve SIGFE +spawnvp SIGFE +_spawnvp = spawnvp SIGFE +spawnvpe SIGFE +_spawnvpe = spawnvpe SIGFE +sprintf SIGFE +_sprintf = sprintf SIGFE +sqrt NOSIGFE +_sqrt = sqrt NOSIGFE +sqrtf NOSIGFE +_sqrtf = sqrtf NOSIGFE +srand NOSIGFE +_srand = srand NOSIGFE +srand48 NOSIGFE +_srand48 = srand48 NOSIGFE +srandom NOSIGFE +__srget SIGFE +__srget_r SIGFE +sscanf SIGFE +_sscanf = sscanf SIGFE +sscanf_r = _sscanf_r SIGFE +_sscanf_r SIGFE +stat SIGFE +_stat = stat SIGFE +_stat64 = stat64 SIGFE +statfs SIGFE +_statfs = statfs SIGFE +statvfs SIGFE +strcasecmp NOSIGFE +_strcasecmp = strcasecmp NOSIGFE +strcat NOSIGFE +_strcat = strcat NOSIGFE +strchr NOSIGFE +_strchr = strchr NOSIGFE +strcmp NOSIGFE +_strcmp = strcmp NOSIGFE +strcoll NOSIGFE +_strcoll = strcoll NOSIGFE +strcpy NOSIGFE +_strcpy = strcpy NOSIGFE +strcspn NOSIGFE +_strcspn = strcspn NOSIGFE +strdup SIGFE +_strdup = strdup SIGFE +strerror SIGFE +_strerror = strerror SIGFE +strerror_r SIGFE +_strerror_r = strerror_r SIGFE +strftime SIGFE +_strftime = strftime SIGFE +strlcat NOSIGFE +_strlcat = strlcat NOSIGFE +strlcpy NOSIGFE +_strlcpy = strlcpy NOSIGFE +strlen NOSIGFE +_strlen = strlen NOSIGFE +strlwr NOSIGFE +_strlwr = strlwr NOSIGFE +strncasecmp NOSIGFE +_strncasecmp = strncasecmp NOSIGFE +strncat NOSIGFE +_strncat = strncat NOSIGFE +strncmp NOSIGFE +_strncmp = strncmp NOSIGFE +strncpy NOSIGFE +_strncpy = strncpy NOSIGFE +strndup SIGFE +strnlen NOSIGFE +strpbrk NOSIGFE +_strpbrk = strpbrk NOSIGFE +strptime SIGFE +_strptime = strptime SIGFE +strrchr NOSIGFE +_strrchr = strrchr NOSIGFE +strsep NOSIGFE +_strsep = strsep NOSIGFE +strsignal SIGFE +strspn NOSIGFE +_strspn = strspn NOSIGFE +strstr NOSIGFE +_strstr = strstr NOSIGFE +strtod SIGFE +_strtod = strtod SIGFE +strtodf = strtof SIGFE +_strtodf = strtof SIGFE +strtof SIGFE +strtoimax = strtoll NOSIGFE +strtok NOSIGFE +_strtok = strtok NOSIGFE +strtok_r NOSIGFE +_strtok_r = strtok_r NOSIGFE +strtol NOSIGFE +_strtol = strtol NOSIGFE +_strtold SIGFE +strtoll NOSIGFE +_strtoll = strtoll NOSIGFE +strtosigno NOSIGFE +strtoul NOSIGFE +_strtoul = strtoul NOSIGFE +strtoull NOSIGFE +_strtoull = strtoull NOSIGFE +strtoumax = strtoull NOSIGFE +strupr NOSIGFE +_strupr = strupr NOSIGFE +strxfrm NOSIGFE +_strxfrm = strxfrm NOSIGFE +swab NOSIGFE +_swab = swab NOSIGFE +__swbuf SIGFE +__swbuf_r SIGFE +symlink SIGFE +_symlink = symlink SIGFE +sync SIGFE +sysconf SIGFE +_sysconf = sysconf SIGFE +syslog SIGFE +_syslog = syslog SIGFE +system SIGFE +_system = system SIGFE +tan NOSIGFE +_tan = tan NOSIGFE +tanf NOSIGFE +_tanf = tanf NOSIGFE +tanh NOSIGFE +_tanh = tanh NOSIGFE +tanhf NOSIGFE +_tanhf = tanhf NOSIGFE +tcdrain SIGFE +_tcdrain = tcdrain SIGFE +tcflow SIGFE +_tcflow = tcflow SIGFE +tcflush SIGFE +_tcflush = tcflush SIGFE +tcgetattr SIGFE +_tcgetattr = tcgetattr SIGFE +tcgetpgrp SIGFE +_tcgetpgrp = tcgetpgrp SIGFE +tcsendbreak SIGFE +_tcsendbreak = tcsendbreak SIGFE +tcsetattr SIGFE +_tcsetattr = tcsetattr SIGFE +tcsetpgrp SIGFE +_tcsetpgrp = tcsetpgrp SIGFE +tdelete SIGFE +tdestroy NOSIGFE +telldir SIGFE +_telldir = telldir SIGFE +_telldir64 = telldir64 SIGFE +tempnam SIGFE +_tempnam = tempnam SIGFE +tfind NOSIGFE +tgamma NOSIGFE +tgammaf NOSIGFE +time SIGFE +_time = time SIGFE +timegm NOSIGFE +timelocal SIGFE +timer_create SIGFE +timer_delete SIGFE +timer_gettime SIGFE +timer_settime SIGFE +times SIGFE +_times = times SIGFE +timezone SIGFE +tmpfile SIGFE +_tmpfile = tmpfile SIGFE +_tmpfile64 = tmpfile64 SIGFE +tmpnam SIGFE +_tmpnam = tmpnam SIGFE +toascii NOSIGFE +_toascii = toascii NOSIGFE +tolower NOSIGFE +_tolower = tolower NOSIGFE +toupper NOSIGFE +_toupper = toupper NOSIGFE +towctrans NOSIGFE +towlower NOSIGFE +towupper NOSIGFE +trunc NOSIGFE +truncate SIGFE +_truncate = truncate SIGFE +_truncate64 = truncate64 SIGFE +truncf NOSIGFE +tsearch SIGFE +ttyname SIGFE +_ttyname = ttyname SIGFE +ttyname_r SIGFE +ttyslot NOSIGFE +twalk NOSIGFE +tzset SIGFE +_tzset = tzset SIGFE +ualarm SIGFE +_ualarm = ualarm SIGFE +umask NOSIGFE +_umask = umask NOSIGFE +umount SIGFE +_umount = umount SIGFE +uname SIGFE +_uname = uname SIGFE +ungetc SIGFE +_ungetc = ungetc SIGFE +unlink SIGFE +_unlink = unlink SIGFE +unlockpt NOSIGFE +unsetenv SIGFE +_unsetenv = unsetenv SIGFE +updwtmp SIGFE +updwtmpx SIGFE +usleep SIGFE +_usleep = usleep SIGFE +utime SIGFE +_utime = utime SIGFE +utimes SIGFE +_utimes = utimes SIGFE +utmpname SIGFE +_utmpname = utmpname SIGFE +utmpxname SIGFE +valloc SIGFE +vasprintf SIGFE +_vasprintf = vasprintf SIGFE +vasprintf_r = _vasprintf_r SIGFE +_vasprintf_r SIGFE +verr SIGFE +verrx SIGFE +vfiprintf SIGFE +_vfiprintf = vfiprintf SIGFE +vfork SIGFE +_vfork = vfork SIGFE +vfprintf SIGFE +_vfprintf = vfprintf SIGFE +vfscanf SIGFE +_vfscanf = vfscanf SIGFE +vfscanf_r = _vfscanf_r SIGFE +_vfscanf_r SIGFE +vhangup SIGFE +_vhangup = vhangup SIGFE +vprintf SIGFE +_vprintf = vprintf SIGFE +vscanf SIGFE +_vscanf = vscanf SIGFE +vscanf_r = _vscanf_r SIGFE +_vscanf_r SIGFE +vsnprintf SIGFE +_vsnprintf = vsnprintf SIGFE +vsprintf SIGFE +_vsprintf = vsprintf SIGFE +vsscanf SIGFE +_vsscanf = vsscanf SIGFE +vsscanf_r = _vsscanf_r SIGFE +_vsscanf_r SIGFE +vsyslog SIGFE +vwarn SIGFE +vwarnx SIGFE +wait SIGFE +_wait = wait SIGFE +wait3 SIGFE +wait4 SIGFE +waitpid SIGFE +_waitpid = waitpid SIGFE +warn SIGFE +warnx SIGFE +wcrtomb NOSIGFE +wcscat NOSIGFE +wcschr NOSIGFE +wcscmp NOSIGFE +_wcscmp = wcscmp NOSIGFE +wcscoll NOSIGFE +wcscpy NOSIGFE +wcscspn NOSIGFE +wcslcat NOSIGFE +wcslcpy NOSIGFE +wcslen NOSIGFE +_wcslen = wcslen NOSIGFE +wcsncat NOSIGFE +wcsncmp NOSIGFE +wcsncpy NOSIGFE +wcspbrk NOSIGFE +wcsrchr NOSIGFE +wcsrtombs NOSIGFE +wcsspn NOSIGFE +wcsstr NOSIGFE +wcstombs NOSIGFE +_wcstombs = wcstombs NOSIGFE +wcswidth NOSIGFE +wctob NOSIGFE +wctomb NOSIGFE +_wctomb = wctomb NOSIGFE +wctrans NOSIGFE +wctype NOSIGFE +wcwidth NOSIGFE +wmemchr NOSIGFE +wmemcmp NOSIGFE +wmemcpy NOSIGFE +wmemmove NOSIGFE +wmemset NOSIGFE +wprintf SIGFE +_wprintf = wprintf SIGFE +write SIGFE +_write = write SIGFE +writev SIGFE +_writev = writev SIGFE +y0 NOSIGFE +y0f NOSIGFE +y1 NOSIGFE +y1f NOSIGFE +yn NOSIGFE +ynf NOSIGFE diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc new file mode 100644 index 00000000000..51d72fc8f90 --- /dev/null +++ b/winsup/cygwin/fhandler_socket.cc @@ -0,0 +1,1694 @@ +/* fhandler_socket.cc. See fhandler.h for a description of the fhandler classes. + + Copyright 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + + This file is part of Cygwin. + + This software is a copyrighted work licensed under the terms of the + Cygwin license. Please consult the file "CYGWIN_LICENSE" for + details. */ + +/* #define DEBUG_NEST_ON 1 */ + +#define __INSIDE_CYGWIN_NET__ + +#include "winsup.h" +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/uio.h> +#include <asm/byteorder.h> + +#include <stdlib.h> +#define USE_SYS_TYPES_FD_SET +#include <winsock2.h> +#include <iphlpapi.h> +#include "cygerrno.h" +#include "security.h" +#include "cygwin/version.h" +#include "perprocess.h" +#include "path.h" +#include "fhandler.h" +#include "dtable.h" +#include "cygheap.h" +#include "sigproc.h" +#include "cygthread.h" +#include "select.h" +#include "wininfo.h" +#include <unistd.h> +#include <sys/acl.h> +#include "cygtls.h" +#include "cygwin/in6.h" + +#define ASYNC_MASK (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT) + +extern bool fdsock (cygheap_fdmanip& fd, const device *, SOCKET soc); +extern "C" { +int sscanf (const char *, const char *, ...); +} /* End of "C" section */ + +fhandler_dev_random* entropy_source; + +/* cygwin internal: map sockaddr into internet domain address */ +static int +get_inet_addr (const struct sockaddr *in, int inlen, + struct sockaddr_storage *out, int *outlen, + int *type = NULL, int *secret = NULL) +{ + int secret_buf [4]; + int* secret_ptr = (secret ? : secret_buf); + + if (in->sa_family == AF_INET || in->sa_family == AF_INET6) + { + memcpy (out, in, inlen); + *outlen = inlen; + return 1; + } + else if (in->sa_family == AF_LOCAL) + { + path_conv pc (in->sa_data, PC_SYM_FOLLOW); + if (pc.error) + { + set_errno (pc.error); + return 0; + } + if (!pc.exists ()) + { + set_errno (ENOENT); + return 0; + } + if (!pc.issocket ()) + { + set_errno (EBADF); + return 0; + } + HANDLE fh = CreateFile (pc, GENERIC_READ, wincap.shared (), &sec_none, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (fh == INVALID_HANDLE_VALUE) + { + __seterrno (); + return 0; + } + int ret = 0; + DWORD len = 0; + char buf[128]; + memset (buf, 0, sizeof buf); + if (ReadFile (fh, buf, 128, &len, 0)) + { + struct sockaddr_in sin; + char ctype; + sin.sin_family = AF_INET; + sscanf (buf + strlen (SOCKET_COOKIE), "%hu %c %08x-%08x-%08x-%08x", + &sin.sin_port, + &ctype, + secret_ptr, secret_ptr + 1, secret_ptr + 2, secret_ptr + 3); + sin.sin_port = htons (sin.sin_port); + sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + memcpy (out, &sin, sizeof sin); + *outlen = sizeof sin; + if (type) + *type = (ctype == 's' ? SOCK_STREAM : + ctype == 'd' ? SOCK_DGRAM + : 0); + ret = 1; + } + else + __seterrno (); + CloseHandle (fh); + return ret; + } + else + { + set_errno (EAFNOSUPPORT); + return 0; + } +} + +/**********************************************************************/ +/* fhandler_socket */ + +fhandler_socket::fhandler_socket () : + fhandler_base (), + sun_path (NULL), + status () +{ + need_fork_fixup (true); + prot_info_ptr = (LPWSAPROTOCOL_INFOA) cmalloc (HEAP_BUF, + sizeof (WSAPROTOCOL_INFOA)); +#if 0 + if (pc.is_fs_special ()) + { + fhandler_socket * fhs = (fhandler_socket *) fh; + fhs->set_addr_family (AF_LOCAL); + fhs->set_sun_path (posix_path); + } +#endif +} + +fhandler_socket::~fhandler_socket () +{ + if (prot_info_ptr) + cfree (prot_info_ptr); + if (sun_path) + cfree (sun_path); +} + +char * +fhandler_socket::get_proc_fd_name (char *buf) +{ + __small_sprintf (buf, "socket:[%d]", get_socket ()); + return buf; +} + +int +fhandler_socket::open (int flags, mode_t mode) +{ + set_errno (ENXIO); + return 0; +} + +void +fhandler_socket::af_local_set_sockpair_cred () +{ + sec_pid = sec_peer_pid = getpid (); + sec_uid = sec_peer_uid = geteuid32 (); + sec_gid = sec_peer_gid = getegid32 (); +} + +void +fhandler_socket::af_local_setblocking (bool &async, bool &nonblocking) +{ + async = async_io (); + nonblocking = is_nonblocking (); + if (async || nonblocking) + WSAAsyncSelect (get_socket (), winmsg, 0, 0); + unsigned long p = 0; + ioctlsocket (get_socket (), FIONBIO, &p); + set_nonblocking (false); + async_io (false); +} + +void +fhandler_socket::af_local_unsetblocking (bool async, bool nonblocking) +{ + if (nonblocking) + { + unsigned long p = 1; + ioctlsocket (get_socket (), FIONBIO, &p); + set_nonblocking (true); + } + if (async) + { + WSAAsyncSelect (get_socket (), winmsg, WM_ASYNCIO, ASYNC_MASK); + async_io (true); + } +} + +bool +fhandler_socket::af_local_recv_secret () +{ + int out[4] = { 0, 0, 0, 0 }; + int rest = sizeof out; + char *ptr = (char *) out; + while (rest > 0) + { + int ret = recvfrom (ptr, rest, 0, NULL, NULL); + if (ret <= 0) + break; + rest -= ret; + ptr += ret; + } + if (rest == 0) + { + debug_printf ("Received af_local secret: %08x-%08x-%08x-%08x", + out[0], out[1], out[2], out[3]); + if (out[0] != connect_secret[0] || out[1] != connect_secret[1] + || out[2] != connect_secret[2] || out[3] != connect_secret[3]) + { + debug_printf ("Receiving af_local secret mismatch"); + return false; + } + } + else + debug_printf ("Receiving af_local secret failed"); + return rest == 0; +} + +bool +fhandler_socket::af_local_send_secret () +{ + int rest = sizeof connect_secret; + char *ptr = (char *) connect_secret; + while (rest > 0) + { + int ret = sendto (ptr, rest, 0, NULL, 0); + if (ret <= 0) + break; + rest -= ret; + ptr += ret; + } + debug_printf ("Sending af_local secret %s", rest == 0 ? "succeeded" + : "failed"); + return rest == 0; +} + +bool +fhandler_socket::af_local_recv_cred () +{ + struct ucred out = { (pid_t) 0, (__uid32_t) -1, (__gid32_t) -1 }; + int rest = sizeof out; + char *ptr = (char *) &out; + while (rest > 0) + { + int ret = recvfrom (ptr, rest, 0, NULL, NULL); + if (ret <= 0) + break; + rest -= ret; + ptr += ret; + } + if (rest == 0) + { + debug_printf ("Received eid credentials: pid: %d, uid: %d, gid: %d", + out.pid, out.uid, out.gid); + sec_peer_pid = out.pid; + sec_peer_uid = out.uid; + sec_peer_gid = out.gid; + } + else + debug_printf ("Receiving eid credentials failed"); + return rest == 0; +} + +bool +fhandler_socket::af_local_send_cred () +{ + struct ucred in = { sec_pid, sec_uid, sec_gid }; + int rest = sizeof in; + char *ptr = (char *) ∈ + while (rest > 0) + { + int ret = sendto (ptr, rest, 0, NULL, 0); + if (ret <= 0) + break; + rest -= ret; + ptr += ret; + } + if (rest == 0) + debug_printf ("Sending eid credentials succeeded"); + else + debug_printf ("Sending eid credentials failed"); + return rest == 0; +} + +int +fhandler_socket::af_local_connect () +{ + /* This keeps the test out of select. */ + if (get_addr_family () != AF_LOCAL || get_socket_type () != SOCK_STREAM) + return 0; + + debug_printf ("af_local_connect called"); + bool orig_async_io, orig_is_nonblocking; + af_local_setblocking (orig_async_io, orig_is_nonblocking); + if (!af_local_send_secret () || !af_local_recv_secret () + || !af_local_send_cred () || !af_local_recv_cred ()) + { + debug_printf ("accept from unauthorized server"); + ::shutdown (get_socket (), SD_BOTH); + WSASetLastError (WSAECONNREFUSED); + return -1; + } + af_local_unsetblocking (orig_async_io, orig_is_nonblocking); + return 0; +} + +int +fhandler_socket::af_local_accept () +{ + debug_printf ("af_local_accept called"); + bool orig_async_io, orig_is_nonblocking; + af_local_setblocking (orig_async_io, orig_is_nonblocking); + if (!af_local_recv_secret () || !af_local_send_secret () + || !af_local_recv_cred () || !af_local_send_cred ()) + { + debug_printf ("connect from unauthorized client"); + ::shutdown (get_socket (), SD_BOTH); + ::closesocket (get_socket ()); + WSASetLastError (WSAECONNABORTED); + return -1; + } + af_local_unsetblocking (orig_async_io, orig_is_nonblocking); + return 0; +} + +void +fhandler_socket::af_local_set_cred () +{ + sec_pid = getpid (); + sec_uid = geteuid32 (); + sec_gid = getegid32 (); + sec_peer_pid = (pid_t) 0; + sec_peer_uid = (__uid32_t) -1; + sec_peer_gid = (__gid32_t) -1; +} + +void +fhandler_socket::af_local_copy (fhandler_socket *sock) +{ + sock->connect_secret[0] = connect_secret[0]; + sock->connect_secret[1] = connect_secret[1]; + sock->connect_secret[2] = connect_secret[2]; + sock->connect_secret[3] = connect_secret[3]; + sock->sec_pid = sec_pid; + sock->sec_uid = sec_uid; + sock->sec_gid = sec_gid; + sock->sec_peer_pid = sec_peer_pid; + sock->sec_peer_uid = sec_peer_uid; + sock->sec_peer_gid = sec_peer_gid; +} + +void +fhandler_socket::af_local_set_secret (char *buf) +{ + if (!entropy_source) + { + void *buf = malloc (sizeof (fhandler_dev_random)); + entropy_source = new (buf) fhandler_dev_random (); + entropy_source->dev () = *urandom_dev; + } + if (entropy_source && + !entropy_source->open (O_RDONLY)) + { + delete entropy_source; + entropy_source = NULL; + } + if (entropy_source) + { + size_t len = sizeof (connect_secret); + entropy_source->read (connect_secret, len); + if (len != sizeof (connect_secret)) + bzero ((char*) connect_secret, sizeof (connect_secret)); + } + __small_sprintf (buf, "%08x-%08x-%08x-%08x", + connect_secret [0], connect_secret [1], + connect_secret [2], connect_secret [3]); +} + +void +fhandler_socket::fixup_before_fork_exec (DWORD win_proc_id) +{ + if (!WSADuplicateSocketA (get_socket (), win_proc_id, prot_info_ptr)) + debug_printf ("WSADuplicateSocket went fine, sock %p, win_proc_id %d, prot_info_ptr %p", + get_socket (), win_proc_id, prot_info_ptr); + else + { + debug_printf ("WSADuplicateSocket error, sock %p, win_proc_id %d, prot_info_ptr %p", + get_socket (), win_proc_id, prot_info_ptr); + set_winsock_errno (); + } +} + +void +fhandler_socket::fixup_after_fork (HANDLE parent) +{ + SOCKET new_sock; + + debug_printf ("WSASocket begin, dwServiceFlags1=%d", + prot_info_ptr->dwServiceFlags1); + + if ((new_sock = WSASocketA (FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + prot_info_ptr, 0, 0)) == INVALID_SOCKET) + { + debug_printf ("WSASocket error"); + set_io_handle ((HANDLE)INVALID_SOCKET); + set_winsock_errno (); + } + else + { + debug_printf ("WSASocket went fine new_sock %p, old_sock %p", new_sock, get_socket ()); + + /* Go figure! Even though the original socket was not inheritable, + the duplicated socket is inheritable again. This can lead to all + sorts of trouble, apparently. Note that there's no way to prevent + this on 9x, not even by trying to reset socket inheritance using + DuplicateHandle and closing the original socket. */ + if (wincap.has_set_handle_information ()) + SetHandleInformation ((HANDLE) new_sock, HANDLE_FLAG_INHERIT, 0); + + set_io_handle ((HANDLE) new_sock); + } +} + +void +fhandler_socket::fixup_after_exec () +{ + if (!close_on_exec ()) + fixup_after_fork (NULL); +} + +int +fhandler_socket::dup (fhandler_base *child) +{ + HANDLE nh; + + debug_printf ("here"); + fhandler_socket *fhs = (fhandler_socket *) child; + fhs->addr_family = addr_family; + fhs->set_socket_type (get_socket_type ()); + if (get_addr_family () == AF_LOCAL) + { + fhs->set_sun_path (get_sun_path ()); + if (get_socket_type () == SOCK_STREAM) + { + fhs->sec_pid = sec_pid; + fhs->sec_uid = sec_uid; + fhs->sec_gid = sec_gid; + fhs->sec_peer_pid = sec_peer_pid; + fhs->sec_peer_uid = sec_peer_uid; + fhs->sec_peer_gid = sec_peer_gid; + } + } + fhs->connect_state (connect_state ()); + + /* Since WSADuplicateSocket() fails on NT systems when the process + is currently impersonating a non-privileged account, we revert + to the original account before calling WSADuplicateSocket() and + switch back afterwards as it's also in fork(). + If WSADuplicateSocket() still fails for some reason, we fall back + to DuplicateHandle(). */ + WSASetLastError (0); + cygheap->user.deimpersonate (); + fhs->set_io_handle (get_io_handle ()); + fhs->fixup_before_fork_exec (GetCurrentProcessId ()); + cygheap->user.reimpersonate (); + if (!WSAGetLastError ()) + { + fhs->fixup_after_fork (hMainProc); + if (fhs->get_io_handle() != (HANDLE) INVALID_SOCKET) + { + cygheap->fdtab.inc_need_fixup_before (); + return 0; + } + } + debug_printf ("WSADuplicateSocket failed, trying DuplicateHandle"); + + /* We don't call fhandler_base::dup here since that requires + having winsock called from fhandler_base and it creates only + inheritable sockets which is wrong for winsock2. */ + + if (!DuplicateHandle (hMainProc, get_io_handle (), hMainProc, &nh, 0, + FALSE, DUPLICATE_SAME_ACCESS)) + { + system_printf ("!DuplicateHandle(%x) failed, %E", get_io_handle ()); + __seterrno (); + return -1; + } + VerifyHandle (nh); + fhs->set_io_handle (nh); + cygheap->fdtab.inc_need_fixup_before (); + return 0; +} + +int __stdcall +fhandler_socket::fstat (struct __stat64 *buf) +{ + int res; + if (get_device () == FH_UNIX) + { + res = fhandler_base::fstat_fs (buf); + if (!res) + { + buf->st_mode = (buf->st_mode & ~S_IFMT) | S_IFSOCK; + } + } + else + { + res = fhandler_base::fstat (buf); + if (!res) + { + buf->st_dev = 0; + buf->st_ino = (__ino64_t) ((DWORD) get_handle ()); + buf->st_mode = S_IFSOCK | S_IRWXU | S_IRWXG | S_IRWXO; + } + } + return res; +} + +int +fhandler_socket::fchmod (mode_t mode) +{ + if (get_device () == FH_UNIX) + { + fhandler_disk_file fh (pc); + fh.get_device () = FH_FS; + int ret = fh.fchmod (mode); + SetFileAttributes (pc, GetFileAttributes (pc) | FILE_ATTRIBUTE_SYSTEM); + return ret; + } + return 0; +} + +int +fhandler_socket::fchown (__uid32_t uid, __gid32_t gid) +{ + if (get_device () == FH_UNIX) + { + fhandler_disk_file fh (pc); + return fh.fchown (uid, gid); + } + return 0; +} + +int +fhandler_socket::facl (int cmd, int nentries, __aclent32_t *aclbufp) +{ + if (get_device () == FH_UNIX) + { + fhandler_disk_file fh (pc); + return fh.facl (cmd, nentries, aclbufp); + } + return fhandler_base::facl (cmd, nentries, aclbufp); +} + +int +fhandler_socket::link (const char *newpath) +{ + if (get_device () == FH_UNIX) + { + fhandler_disk_file fh (pc); + return fh.link (newpath); + } + return fhandler_base::link (newpath); +} + +static inline bool +address_in_use (struct sockaddr_in *addr) +{ + PMIB_TCPTABLE tab; + PMIB_TCPROW entry; + DWORD size = 0, i; + + if (GetTcpTable (NULL, &size, FALSE) == ERROR_INSUFFICIENT_BUFFER) + { + tab = (PMIB_TCPTABLE) alloca (size); + if (!GetTcpTable (tab, &size, FALSE)) + { + for (i = tab->dwNumEntries, entry = tab->table; i > 0; --i, ++entry) + if (entry->dwLocalAddr == addr->sin_addr.s_addr + && entry->dwLocalPort == addr->sin_port + && entry->dwState >= MIB_TCP_STATE_LISTEN + && entry->dwState <= MIB_TCP_STATE_LAST_ACK) + return true; + } + } + return false; +} + +int +fhandler_socket::bind (const struct sockaddr *name, int namelen) +{ + int res = -1; + + if (name->sa_family == AF_LOCAL) + { +#define un_addr ((struct sockaddr_un *) name) + struct sockaddr_in sin; + int len = sizeof sin; + + if (strlen (un_addr->sun_path) >= UNIX_PATH_LEN) + { + set_errno (ENAMETOOLONG); + goto out; + } + sin.sin_family = AF_INET; + sin.sin_port = 0; + sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + if (::bind (get_socket (), (sockaddr *) &sin, len)) + { + syscall_printf ("AF_LOCAL: bind failed %d", get_errno ()); + set_winsock_errno (); + goto out; + } + if (::getsockname (get_socket (), (sockaddr *) &sin, &len)) + { + syscall_printf ("AF_LOCAL: getsockname failed %d", get_errno ()); + set_winsock_errno (); + goto out; + } + + sin.sin_port = ntohs (sin.sin_port); + debug_printf ("AF_LOCAL: socket bound to port %u", sin.sin_port); + + path_conv pc (un_addr->sun_path, PC_SYM_FOLLOW); + if (pc.error) + { + set_errno (pc.error); + goto out; + } + if (pc.exists ()) + { + set_errno (EADDRINUSE); + goto out; + } + mode_t mode = (S_IRWXU | S_IRWXG | S_IRWXO) & ~cygheap->umask; + DWORD attr = FILE_ATTRIBUTE_SYSTEM; + if (!(mode & (S_IWUSR | S_IWGRP | S_IWOTH))) + attr |= FILE_ATTRIBUTE_READONLY; + SECURITY_ATTRIBUTES sa = sec_none; + security_descriptor sd; + if (allow_ntsec && pc.has_acls ()) + set_security_attribute (mode, &sa, sd); + HANDLE fh = CreateFile (pc, GENERIC_WRITE, 0, &sa, CREATE_NEW, attr, 0); + if (fh == INVALID_HANDLE_VALUE) + { + if (GetLastError () == ERROR_ALREADY_EXISTS) + set_errno (EADDRINUSE); + else + __seterrno (); + } + + char buf[sizeof (SOCKET_COOKIE) + 80]; + __small_sprintf (buf, "%s%u %c ", SOCKET_COOKIE, sin.sin_port, get_socket_type () == SOCK_STREAM ? 's' : get_socket_type () == SOCK_DGRAM ? 'd' : '-'); + af_local_set_secret (strchr (buf, '\0')); + DWORD blen = strlen (buf) + 1; + if (!WriteFile (fh, buf, blen, &blen, 0)) + { + __seterrno (); + CloseHandle (fh); + DeleteFile (pc); + } + else + { + CloseHandle (fh); + set_sun_path (un_addr->sun_path); + res = 0; + } +#undef un_addr + } + else + { + /* If the application didn't explicitely call setsockopt (SO_REUSEADDR), + enforce exclusive local address use using the SO_EXCLUSIVEADDRUSE + socket option, to emulate POSIX socket behaviour more closely. + + KB 870562: Note that this option is only available since NT4 SP4. + Also note that a bug in Win2K SP1-3 and XP up to SP1 only enables + this option for users in the local administrators group. */ + if (wincap.has_exclusiveaddruse ()) + { + if (!saw_reuseaddr ()) + { + int on = 1; + int ret = ::setsockopt (get_socket (), SOL_SOCKET, + ~(SO_REUSEADDR), + (const char *) &on, sizeof on); + debug_printf ("%d = setsockopt (SO_EXCLUSIVEADDRUSE), %E", ret); + } + else + { + debug_printf ("SO_REUSEADDR set"); + /* There's a bug in SO_REUSEADDR handling in WinSock. + Per standards, we must not be able to reuse a complete + duplicate of a local TCP address (same IP, same port), + even if SO_REUSEADDR has been set. That's unfortunately + possible in WinSock. So we're testing here if the local + address is already in use and don't bind, if so. This + only works for OSes with IP Helper support. */ + if (get_socket_type () == SOCK_STREAM + && wincap.has_ip_helper_lib () + && address_in_use ((struct sockaddr_in *) name)) + { + debug_printf ("Local address in use, don't bind"); + set_errno (EADDRINUSE); + goto out; + } + } + } + if (::bind (get_socket (), name, namelen)) + set_winsock_errno (); + else + res = 0; + } + +out: + return res; +} + +int +fhandler_socket::connect (const struct sockaddr *name, int namelen) +{ + int res = -1; + bool in_progress = false; + struct sockaddr_storage sst; + DWORD err; + int type; + + if (!get_inet_addr (name, namelen, &sst, &namelen, &type, connect_secret)) + return -1; + + if (get_addr_family () == AF_LOCAL && get_socket_type () != type) + { + WSASetLastError (WSAEPROTOTYPE); + set_winsock_errno (); + return -1; + } + + res = ::connect (get_socket (), (struct sockaddr *) &sst, namelen); + + if (!res) + err = 0; + else + { + err = WSAGetLastError (); + /* Special handling for connect to return the correct error code + when called on a non-blocking socket. */ + if (is_nonblocking ()) + { + if (err == WSAEWOULDBLOCK || err == WSAEALREADY) + in_progress = true; + + if (err == WSAEWOULDBLOCK) + WSASetLastError (err = WSAEINPROGRESS); + } + if (err == WSAEINVAL) + WSASetLastError (err = WSAEISCONN); + set_winsock_errno (); + } + + if (get_addr_family () == AF_LOCAL && (!res || in_progress)) + set_sun_path (name->sa_data); + + if (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM) + { + af_local_set_cred (); /* Don't move into af_local_connect since + af_local_connect is called from select, + possibly running under another identity. */ + if (!res && af_local_connect ()) + { + set_winsock_errno (); + return -1; + } + } + + if (err == WSAEINPROGRESS || err == WSAEALREADY) + connect_state (connect_pending); + else if (err) + connect_state (connect_failed); + else + connect_state (connected); + + return res; +} + +int +fhandler_socket::listen (int backlog) +{ + int res = ::listen (get_socket (), backlog); + if (res && WSAGetLastError () == WSAEINVAL) + { + /* It's perfectly valid to call listen on an unbound INET socket. + In this case the socket is automatically bound to an unused + port number, listening on all interfaces. On Winsock, listen + fails with WSAEINVAL when it's called on an unbound socket. + So we have to bind manually here to have POSIX semantics. */ + if (get_addr_family () == AF_INET) + { + struct sockaddr_in sin; + sin.sin_family = AF_INET; + sin.sin_port = 0; + sin.sin_addr.s_addr = INADDR_ANY; + if (!::bind (get_socket (), (struct sockaddr *) &sin, sizeof sin)) + res = ::listen (get_socket (), backlog); + } + else if (get_addr_family () == AF_INET6) + { + struct sockaddr_in6 sin6 = + { + sin6_family: AF_INET6, + sin6_port: 0, + sin6_flowinfo: 0, + sin6_addr: IN6ADDR_ANY_INIT, + sin6_scope_id: 0 + }; + if (!::bind (get_socket (), (struct sockaddr *) &sin6, sizeof sin6)) + res = ::listen (get_socket (), backlog); + } + } + if (!res) + { + if (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM) + af_local_set_cred (); + connect_state (connected); + } + else + set_winsock_errno (); + return res; +} + +int +fhandler_socket::accept (struct sockaddr *peer, int *len) +{ + int res = -1; + + /* Allows NULL peer and len parameters. */ + struct sockaddr_in peer_dummy; + int len_dummy; + if (!peer) + peer = (struct sockaddr *) &peer_dummy; + if (!len) + { + len_dummy = sizeof (struct sockaddr_in); + len = &len_dummy; + } + + /* accept on NT fails if len < sizeof (sockaddr_in) + * some programs set len to + * sizeof (name.sun_family) + strlen (name.sun_path) for UNIX domain + */ + if (len && ((unsigned) *len < sizeof (struct sockaddr_in))) + *len = sizeof (struct sockaddr_in); + + res = ::accept (get_socket (), peer, len); + + if (res == (int) INVALID_SOCKET) + set_winsock_errno (); + else + { + cygheap_fdnew res_fd; + if (res_fd >= 0 && fdsock (res_fd, &dev (), res)) + { + fhandler_socket *sock = (fhandler_socket *) res_fd; + sock->set_addr_family (get_addr_family ()); + sock->set_socket_type (get_socket_type ()); + sock->async_io (async_io ()); + sock->set_nonblocking (is_nonblocking ()); + if (get_addr_family () == AF_LOCAL) + { + sock->set_sun_path (get_sun_path ()); + if (get_socket_type () == SOCK_STREAM) + { + /* Don't forget to copy credentials from accepting + socket to accepted socket and start transaction + on accepted socket! */ + af_local_copy (sock); + res = sock->af_local_accept (); + if (res == -1) + { + res_fd.release (); + set_winsock_errno (); + goto out; + } + } + } + sock->connect_state (connected); + res = res_fd; + } + else + { + closesocket (res); + res = -1; + } + } + +out: + debug_printf ("res %d", res); + return res; +} + +int +fhandler_socket::getsockname (struct sockaddr *name, int *namelen) +{ + int res = -1; + + if (get_addr_family () == AF_LOCAL) + { + struct sockaddr_un *sun = (struct sockaddr_un *) name; + memset (sun, 0, *namelen); + sun->sun_family = AF_LOCAL; + + if (!get_sun_path ()) + sun->sun_path[0] = '\0'; + else + /* According to SUSv2 "If the actual length of the address is + greater than the length of the supplied sockaddr structure, the + stored address will be truncated." We play it save here so + that the path always has a trailing 0 even if it's truncated. */ + strncpy (sun->sun_path, get_sun_path (), + *namelen - sizeof *sun + sizeof sun->sun_path - 1); + + *namelen = sizeof *sun - sizeof sun->sun_path + + strlen (sun->sun_path) + 1; + res = 0; + } + else + { + res = ::getsockname (get_socket (), name, namelen); + if (res) + set_winsock_errno (); + } + + return res; +} + +int +fhandler_socket::getpeername (struct sockaddr *name, int *namelen) +{ + int res = ::getpeername (get_socket (), name, namelen); + if (res) + set_winsock_errno (); + + return res; +} + +bool +fhandler_socket::prepare (HANDLE &event, long event_mask) +{ + WSASetLastError (0); + closed (false); + if ((event = WSACreateEvent ()) == WSA_INVALID_EVENT) + { + debug_printf ("WSACreateEvent, %E"); + return false; + } + if (WSAEventSelect (get_socket (), event, event_mask) == SOCKET_ERROR) + { + debug_printf ("WSAEventSelect(evt), %d", WSAGetLastError ()); + return false; + } + return true; +} + +int +fhandler_socket::wait (HANDLE event, int flags, DWORD timeout) +{ + int ret = SOCKET_ERROR; + int wsa_err = 0; + WSAEVENT ev[2] = { event, signal_arrived }; + WSANETWORKEVENTS evts; + +/* If WSAWaitForMultipleEvents is interrupted by a signal, and the signal + has the SA_RESTART flag set, return to this label and... restart. */ +sa_restart: + + switch (WSAWaitForMultipleEvents (2, ev, FALSE, timeout, FALSE)) + { + case WSA_WAIT_TIMEOUT: + ret = 0; + break; + case WSA_WAIT_EVENT_0: + if (!WSAEnumNetworkEvents (get_socket (), event, &evts)) + { + if (!evts.lNetworkEvents) + { + ret = 0; + break; + } + if (evts.lNetworkEvents & FD_OOB) + { + if (evts.iErrorCode[FD_OOB_BIT]) + wsa_err = evts.iErrorCode[FD_OOB_BIT]; + else if (flags & MSG_OOB) + ret = 0; + else + { + raise (SIGURG); + WSASetLastError (WSAEINTR); + break; + } + } + if (evts.lNetworkEvents & FD_ACCEPT) + { + if (evts.iErrorCode[FD_ACCEPT_BIT]) + wsa_err = evts.iErrorCode[FD_ACCEPT_BIT]; + else + ret = 0; + } + if (evts.lNetworkEvents & FD_CONNECT) + { + if (evts.iErrorCode[FD_CONNECT_BIT]) + wsa_err = evts.iErrorCode[FD_CONNECT_BIT]; + else + ret = 0; + } + else if (evts.lNetworkEvents & FD_READ) + { + if (evts.iErrorCode[FD_READ_BIT]) + wsa_err = evts.iErrorCode[FD_READ_BIT]; + else + ret = 0; + } + else if (evts.lNetworkEvents & FD_WRITE) + { + if (evts.iErrorCode[FD_WRITE_BIT]) + wsa_err = evts.iErrorCode[FD_WRITE_BIT]; + else + ret = 0; + } + if (evts.lNetworkEvents & FD_CLOSE) + { + closed (true); + if (!wsa_err) + { + if (evts.iErrorCode[FD_CLOSE_BIT]) + wsa_err = evts.iErrorCode[FD_CLOSE_BIT]; + else + ret = 0; + } + } + if (wsa_err) + WSASetLastError (wsa_err); + } + break; + case WSA_WAIT_EVENT_0 + 1: + if (_my_tls.call_signal_handler ()) + { + sig_dispatch_pending (); + goto sa_restart; + } + WSASetLastError (WSAEINTR); + break; + default: + WSASetLastError (WSAEFAULT); + break; + } + return ret; +} + +void +fhandler_socket::release (HANDLE event) +{ + int last_err = WSAGetLastError (); + /* KB 168349: NT4 fails if the event parameter is not NULL. */ + if (WSAEventSelect (get_socket (), NULL, 0) == SOCKET_ERROR) + debug_printf ("WSAEventSelect(NULL), %d", WSAGetLastError ()); + WSACloseEvent (event); + unsigned long non_block = 0; + if (ioctlsocket (get_socket (), FIONBIO, &non_block)) + debug_printf ("return to blocking failed: %d", WSAGetLastError ()); + else + WSASetLastError (last_err); +} + +int +fhandler_socket::readv (const struct iovec *const iov, const int iovcnt, + ssize_t tot) +{ + struct msghdr msg = + { + msg_name: NULL, + msg_namelen: 0, + msg_iov: (struct iovec *) iov, // const_cast + msg_iovlen: iovcnt, + msg_control: NULL, + msg_controllen: 0, + msg_flags: 0 + }; + + return recvmsg (&msg, 0, tot); +} + +int +fhandler_socket::recvfrom (void *ptr, size_t len, int flags, + struct sockaddr *from, int *fromlen) +{ + int res = SOCKET_ERROR; + DWORD ret = 0; + + WSABUF wsabuf = { len, (char *) ptr }; + + if (is_nonblocking () || closed () || async_io ()) + { + DWORD lflags = (DWORD) (flags & MSG_WINMASK); + res = WSARecvFrom (get_socket (), &wsabuf, 1, &ret, + &lflags, from, fromlen, NULL, NULL); + } + else + { + HANDLE evt; + if (prepare (evt, FD_CLOSE | FD_READ | (owner () ? FD_OOB : 0))) + { + do + { + DWORD lflags = (DWORD) (flags & MSG_WINMASK); + res = WSARecvFrom (get_socket (), &wsabuf, 1, &ret, &lflags, + from, fromlen, NULL, NULL); + } + while (res == SOCKET_ERROR + && WSAGetLastError () == WSAEWOULDBLOCK + && !closed () + && !(res = wait (evt, flags))); + release (evt); + } + } + + if (res == SOCKET_ERROR) + { + /* According to SUSv3, errno isn't set in that case and no error + condition is returned. */ + if (WSAGetLastError () == WSAEMSGSIZE) + return len; + + /* ESHUTDOWN isn't defined for recv in SUSv3. Simply EOF is returned + in this case. */ + if (WSAGetLastError () == WSAESHUTDOWN) + return 0; + + set_winsock_errno (); + } + else + res = ret; + + return res; +} + +int +fhandler_socket::recvmsg (struct msghdr *msg, int flags, ssize_t tot) +{ + if (CYGWIN_VERSION_CHECK_FOR_USING_ANCIENT_MSGHDR) + ((struct OLD_msghdr *) msg)->msg_accrightslen = 0; + else + { + msg->msg_controllen = 0; + msg->msg_flags = 0; + } + if (get_addr_family () == AF_LOCAL) + { + /* On AF_LOCAL sockets the (fixed-size) name of the shared memory + area used for descriptor passing is transmitted first. + If this string is empty, no descriptors are passed and we can + go ahead recv'ing the normal data blocks. Otherwise start + special handling for descriptor passing. */ + /*TODO*/ + } + + struct iovec *const iov = msg->msg_iov; + const int iovcnt = msg->msg_iovlen; + + struct sockaddr *from = (struct sockaddr *) msg->msg_name; + int *fromlen = from ? &msg->msg_namelen : NULL; + + int res = SOCKET_ERROR; + + WSABUF wsabuf[iovcnt]; + unsigned long len = 0L; + + const struct iovec *iovptr = iov + iovcnt; + WSABUF *wsaptr = wsabuf + iovcnt; + do + { + iovptr -= 1; + wsaptr -= 1; + len += wsaptr->len = iovptr->iov_len; + wsaptr->buf = (char *) iovptr->iov_base; + } + while (wsaptr != wsabuf); + + DWORD ret = 0; + + if (is_nonblocking () || closed () || async_io ()) + { + DWORD lflags = (DWORD) (flags & MSG_WINMASK); + res = WSARecvFrom (get_socket (), wsabuf, iovcnt, &ret, + &lflags, from, fromlen, NULL, NULL); + } + else + { + HANDLE evt; + if (prepare (evt, FD_CLOSE | FD_READ | (owner () ? FD_OOB : 0))) + { + do + { + DWORD lflags = (DWORD) (flags & MSG_WINMASK); + res = WSARecvFrom (get_socket (), wsabuf, iovcnt, &ret, + &lflags, from, fromlen, NULL, NULL); + } + while (res == SOCKET_ERROR + && WSAGetLastError () == WSAEWOULDBLOCK + && !closed () + && !(res = wait (evt, flags))); + release (evt); + } + } + + if (res == SOCKET_ERROR) + { + /* According to SUSv3, errno isn't set in that case and no error + condition is returned. */ + if (WSAGetLastError () == WSAEMSGSIZE) + return len; + + /* ESHUTDOWN isn't defined for recv in SUSv3. Simply EOF is returned + in this case. */ + if (WSAGetLastError () == WSAESHUTDOWN) + return 0; + + set_winsock_errno (); + } + else + res = ret; + + return res; +} + +int +fhandler_socket::writev (const struct iovec *const iov, const int iovcnt, + ssize_t tot) +{ + struct msghdr msg = + { + msg_name: NULL, + msg_namelen: 0, + msg_iov: (struct iovec *) iov, // const_cast + msg_iovlen: iovcnt, + msg_control: NULL, + msg_controllen: 0, + msg_flags: 0 + }; + + return sendmsg (&msg, 0, tot); +} + +int +fhandler_socket::sendto (const void *ptr, size_t len, int flags, + const struct sockaddr *to, int tolen) +{ + struct sockaddr_storage sst; + + if (to && !get_inet_addr (to, tolen, &sst, &tolen)) + return SOCKET_ERROR; + + int res = SOCKET_ERROR; + DWORD ret = 0; + + WSABUF wsabuf = { len, (char *) ptr }; + + if (is_nonblocking () || closed () || async_io ()) + res = WSASendTo (get_socket (), &wsabuf, 1, &ret, + flags & MSG_WINMASK, + (to ? (const struct sockaddr *) &sst : NULL), tolen, + NULL, NULL); + else + { + HANDLE evt; + if (prepare (evt, FD_CLOSE | FD_WRITE | (owner () ? FD_OOB : 0))) + { + do + { + res = WSASendTo (get_socket (), &wsabuf, 1, &ret, + flags & MSG_WINMASK, + (to ? (const struct sockaddr *) &sst : NULL), + tolen, NULL, NULL); + } + while (res == SOCKET_ERROR + && WSAGetLastError () == WSAEWOULDBLOCK + && !(res = wait (evt, 0)) + && !closed ()); + release (evt); + } + } + + if (res == SOCKET_ERROR) + set_winsock_errno (); + else + res = ret; + + /* Special handling for EPIPE and SIGPIPE. + + EPIPE is generated if the local end has been shut down on a connection + oriented socket. In this case the process will also receive a SIGPIPE + unless MSG_NOSIGNAL is set. */ + if (res == SOCKET_ERROR && get_errno () == ESHUTDOWN + && get_socket_type () == SOCK_STREAM) + { + set_errno (EPIPE); + if (! (flags & MSG_NOSIGNAL)) + raise (SIGPIPE); + } + + return res; +} + +int +fhandler_socket::sendmsg (const struct msghdr *msg, int flags, ssize_t tot) +{ + if (get_addr_family () == AF_LOCAL) + { + /* For AF_LOCAL/AF_UNIX sockets, if descriptors are given, start + the special handling for descriptor passing. Otherwise just + transmit an empty string to tell the receiver that no + descriptor passing is done. */ + /*TODO*/ + } + + struct iovec *const iov = msg->msg_iov; + const int iovcnt = msg->msg_iovlen; + + int res = SOCKET_ERROR; + + WSABUF wsabuf[iovcnt]; + + const struct iovec *iovptr = iov + iovcnt; + WSABUF *wsaptr = wsabuf + iovcnt; + do + { + iovptr -= 1; + wsaptr -= 1; + wsaptr->len = iovptr->iov_len; + wsaptr->buf = (char *) iovptr->iov_base; + } + while (wsaptr != wsabuf); + + DWORD ret = 0; + + if (is_nonblocking () || closed () || async_io ()) + res = WSASendTo (get_socket (), wsabuf, iovcnt, &ret, + flags & MSG_WINMASK, (struct sockaddr *) msg->msg_name, + msg->msg_namelen, NULL, NULL); + else + { + HANDLE evt; + if (prepare (evt, FD_CLOSE | FD_WRITE | (owner () ? FD_OOB : 0))) + { + do + { + res = WSASendTo (get_socket (), wsabuf, iovcnt, + &ret, flags & MSG_WINMASK, + (struct sockaddr *) msg->msg_name, + msg->msg_namelen, NULL, NULL); + } + while (res == SOCKET_ERROR + && WSAGetLastError () == WSAEWOULDBLOCK + && !(res = wait (evt, 0)) + && !closed ()); + release (evt); + } + } + + if (res == SOCKET_ERROR) + set_winsock_errno (); + else + res = ret; + + /* Special handling for EPIPE and SIGPIPE. + + EPIPE is generated if the local end has been shut down on a connection + oriented socket. In this case the process will also receive a SIGPIPE + unless MSG_NOSIGNAL is set. */ + if (res == SOCKET_ERROR && get_errno () == ESHUTDOWN + && get_socket_type () == SOCK_STREAM) + { + set_errno (EPIPE); + if (! (flags & MSG_NOSIGNAL)) + raise (SIGPIPE); + } + + return res; +} + +int +fhandler_socket::shutdown (int how) +{ + int res = ::shutdown (get_socket (), how); + + if (res) + set_winsock_errno (); + else + switch (how) + { + case SHUT_RD: + saw_shutdown_read (true); + break; + case SHUT_WR: + saw_shutdown_write (true); + break; + case SHUT_RDWR: + saw_shutdown_read (true); + saw_shutdown_write (true); + break; + } + return res; +} + +int +fhandler_socket::close () +{ + int res = 0; + + /* HACK to allow a graceful shutdown even if shutdown() hasn't been + called by the application. Note that this isn't the ultimate + solution but it helps in many cases. */ + struct linger linger; + linger.l_onoff = 1; + linger.l_linger = 240; /* secs. default 2MSL value according to MSDN. */ + setsockopt (get_socket (), SOL_SOCKET, SO_LINGER, + (const char *)&linger, sizeof linger); + + while ((res = closesocket (get_socket ())) != 0) + { + if (WSAGetLastError () != WSAEWOULDBLOCK) + { + set_winsock_errno (); + res = -1; + break; + } + if (WaitForSingleObject (signal_arrived, 10) == WAIT_OBJECT_0) + { + set_errno (EINTR); + res = -1; + break; + } + WSASetLastError (0); + } + + debug_printf ("%d = fhandler_socket::close()", res); + return res; +} + +int +fhandler_socket::ioctl (unsigned int cmd, void *p) +{ + extern int get_ifconf (struct ifconf *ifc, int what); /* net.cc */ + int res; + struct ifconf ifc, *ifcp; + struct ifreq *ifr, *ifrp; + + switch (cmd) + { + case SIOCGIFCONF: + ifcp = (struct ifconf *) p; + if (!ifcp) + { + set_errno (EINVAL); + return -1; + } + res = get_ifconf (ifcp, cmd); + if (res) + debug_printf ("error in get_ifconf"); + break; + case SIOCGIFFLAGS: + ifr = (struct ifreq *) p; + if (ifr == 0) + { + set_errno (EINVAL); + return -1; + } + ifr->ifr_flags = IFF_NOTRAILERS | IFF_UP | IFF_RUNNING; + if (!strncmp(ifr->ifr_name, "lo", 2) + || ntohl (((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr) + == INADDR_LOOPBACK) + ifr->ifr_flags |= IFF_LOOPBACK; + else + ifr->ifr_flags |= IFF_BROADCAST; + res = 0; + break; + case SIOCGIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCGIFADDR: + case SIOCGIFHWADDR: + case SIOCGIFMETRIC: + case SIOCGIFMTU: + { + ifc.ifc_len = 2048; + ifc.ifc_buf = (char *) alloca (2048); + + ifr = (struct ifreq *) p; + if (ifr == 0) + { + debug_printf ("ifr == NULL"); + set_errno (EINVAL); + return -1; + } + + res = get_ifconf (&ifc, cmd); + if (res) + { + debug_printf ("error in get_ifconf"); + break; + } + + debug_printf (" name: %s", ifr->ifr_name); + for (ifrp = ifc.ifc_req; + (caddr_t) ifrp < ifc.ifc_buf + ifc.ifc_len; + ++ifrp) + { + debug_printf ("testname: %s", ifrp->ifr_name); + if (! strcmp (ifrp->ifr_name, ifr->ifr_name)) + { + switch (cmd) + { + case SIOCGIFADDR: + ifr->ifr_addr = ifrp->ifr_addr; + break; + case SIOCGIFBRDADDR: + ifr->ifr_broadaddr = ifrp->ifr_broadaddr; + break; + case SIOCGIFNETMASK: + ifr->ifr_netmask = ifrp->ifr_netmask; + break; + case SIOCGIFHWADDR: + ifr->ifr_hwaddr = ifrp->ifr_hwaddr; + break; + case SIOCGIFMETRIC: + ifr->ifr_metric = ifrp->ifr_metric; + break; + case SIOCGIFMTU: + ifr->ifr_mtu = ifrp->ifr_mtu; + break; + } + break; + } + } + if ((caddr_t) ifrp >= ifc.ifc_buf + ifc.ifc_len) + { + set_errno (EINVAL); + return -1; + } + break; + } + case FIOASYNC: + res = WSAAsyncSelect (get_socket (), winmsg, WM_ASYNCIO, + *(int *) p ? ASYNC_MASK : 0); + syscall_printf ("Async I/O on socket %s", + *(int *) p ? "started" : "cancelled"); + async_io (*(int *) p != 0); + break; + case FIONREAD: + res = ioctlsocket (get_socket (), FIONREAD, (unsigned long *) p); + if (res == SOCKET_ERROR) + set_winsock_errno (); + break; + default: + /* We must cancel WSAAsyncSelect (if any) before setting socket to + * blocking mode + */ + if (cmd == FIONBIO && *(int *) p == 0) + { + if (async_io ()) + WSAAsyncSelect (get_socket (), winmsg, 0, 0); + if (WSAEventSelect (get_socket (), NULL, 0) == SOCKET_ERROR) + debug_printf ("WSAEventSelect(NULL), %d", WSAGetLastError ()); + } + res = ioctlsocket (get_socket (), cmd, (unsigned long *) p); + if (res == SOCKET_ERROR) + set_winsock_errno (); + if (cmd == FIONBIO) + { + if (!res) + { + syscall_printf ("socket is now %sblocking", + *(int *) p ? "non" : ""); + set_nonblocking (*(int *) p); + } + /* Start AsyncSelect if async socket unblocked */ + if (*(int *) p && async_io ()) + WSAAsyncSelect (get_socket (), winmsg, WM_ASYNCIO, ASYNC_MASK); + } + break; + } + syscall_printf ("%d = ioctl_socket (%x, %x)", res, cmd, p); + return res; +} + +int +fhandler_socket::fcntl (int cmd, void *arg) +{ + int res = 0; + int request, current; + + switch (cmd) + { + case F_SETOWN: + { + /* Urgh! Bad hack! */ + pid_t pid = (pid_t) arg; + owner (pid == getpid ()); + debug_printf ("owner set to %d", owner ()); + } + break; + case F_SETFL: + { + /* Carefully test for the O_NONBLOCK or deprecated OLD_O_NDELAY flag. + Set only the flag that has been passed in. If both are set, just + record O_NONBLOCK. */ + int new_flags = (int) arg & O_NONBLOCK_MASK; + if ((new_flags & OLD_O_NDELAY) && (new_flags & O_NONBLOCK)) + new_flags = O_NONBLOCK; + current = get_flags () & O_NONBLOCK_MASK; + request = new_flags ? 1 : 0; + if (!!current != !!new_flags && (res = ioctl (FIONBIO, &request))) + break; + set_flags ((get_flags () & ~O_NONBLOCK_MASK) | new_flags); + break; + } + default: + res = fhandler_base::fcntl (cmd, arg); + break; + } + return res; +} + +void +fhandler_socket::set_close_on_exec (bool val) +{ + close_on_exec (val); + debug_printf ("set close_on_exec for %s to %d", get_name (), val); +} + +void +fhandler_socket::set_sun_path (const char *path) +{ + sun_path = path ? cstrdup (path) : NULL; +} + +int +fhandler_socket::getpeereid (pid_t *pid, __uid32_t *euid, __gid32_t *egid) +{ + if (get_addr_family () != AF_LOCAL || get_socket_type () != SOCK_STREAM) + { + set_errno (EINVAL); + return -1; + } + if (connect_state () != connected) + { + set_errno (ENOTCONN); + return -1; + } + if (sec_peer_pid == (pid_t) 0) + { + set_errno (ENOTCONN); /* Usually when calling getpeereid on + accepting (instead of accepted) socket. */ + return -1; + } + + myfault efault; + if (efault.faulted (EFAULT)) + return -1; + if (pid) + *pid = sec_peer_pid; + if (euid) + *euid = sec_peer_uid; + if (egid) + *egid = sec_peer_gid; + return 0; +} diff --git a/winsup/cygwin/include/cygwin/in.h b/winsup/cygwin/include/cygwin/in.h new file mode 100644 index 00000000000..619d47a30d4 --- /dev/null +++ b/winsup/cygwin/include/cygwin/in.h @@ -0,0 +1,209 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions of the Internet Protocol. + * + * Version: @(#)in.h 1.0.1 04/21/93 + * + * Authors: Original taken from the GNU Project <netinet/in.h> file. + * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _CYGWIN_IN_H +#define _CYGWIN_IN_H + +#include <cygwin/socket.h> + +typedef uint16_t in_port_t; +typedef uint32_t in_addr_t; + +/* Standard well-defined IP protocols. If you ever add one here, don't + forget to define it below. */ +enum +{ + IPPROTO_IP = 0, /* Dummy protocol for TCP */ + IPPROTO_HOPOPTS = 0, /* IPv6 Hop-by-Hop options */ + IPPROTO_ICMP = 1, /* Internet Control Message Protocol */ + IPPROTO_IGMP = 2, /* Internet Gateway Management Protocol */ + IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */ + IPPROTO_TCP = 6, /* Transmission Control Protocol */ + IPPROTO_EGP = 8, /* Exterior Gateway Protocol */ + IPPROTO_PUP = 12, /* PUP protocol */ + IPPROTO_UDP = 17, /* User Datagram Protocol */ + IPPROTO_IDP = 22, /* XNS IDP protocol */ + IPPROTO_IPV6 = 41, /* IPv6 header */ + IPPROTO_ROUTING = 43, /* IPv6 Routing header */ + IPPROTO_FRAGMENT = 44, /* IPv6 fragmentation header */ + IPPROTO_ESP = 50, /* encapsulating security payload */ + IPPROTO_AH = 51, /* authentication header */ + IPPROTO_ICMPV6 = 58, /* ICMPv6 */ + IPPROTO_NONE = 59, /* IPv6 no next header */ + IPPROTO_DSTOPTS = 60, /* IPv6 Destination options */ + IPPROTO_RAW = 255, /* Raw IP packets */ + IPPROTO_MAX +}; + +/* Define IPPROTO_xxx values to accomodate SUSv3 */ +#define IPPROTO_IP IPPROTO_IP +#define IPPROTO_HOPOPTS IPPROTO_HOPOPTS +#define IPPROTO_ICMP IPPROTO_ICMP +#define IPPROTO_IGMP IPPROTO_IGMP +#define IPPROTO_IPIP IPPROTO_IPIP +#define IPPROTO_TCP IPPROTO_TCP +#define IPPROTO_EGP IPPROTO_EGP +#define IPPROTO_PUP IPPROTO_PUP +#define IPPROTO_UDP IPPROTO_UDP +#define IPPROTO_IDP IPPROTO_IDP +#define IPPROTO_RAW IPPROTO_RAW +#define IPPROTO_IPV6 IPPROTO_IPV6 +#define IPPROTO_ROUTING IPPROTO_ROUTING +#define IPPROTO_FRAGMENT IPPROTO_FRAGMENT +#define IPPROTO_ESP IPPROTO_ESP +#define IPPROTO_AH IPPROTO_AH +#define IPPROTO_ICMPV6 IPPROTO_ICMPV6 +#define IPPROTO_NONE IPPROTO_NONE +#define IPPROTO_DSTOPTS IPPROTO_DSTOPTS + +/* Standard well-known ports. *//* from winsup/include/netinet/in.h */ +enum +{ + IPPORT_ECHO = 7, /* Echo service. */ + IPPORT_DISCARD = 9, /* Discard transmissions service. */ + IPPORT_SYSTAT = 11, /* System status service. */ + IPPORT_DAYTIME = 13, /* Time of day service. */ + IPPORT_NETSTAT = 15, /* Network status service. */ + IPPORT_FTP = 21, /* File Transfer Protocol. */ + IPPORT_TELNET = 23, /* Telnet protocol. */ + IPPORT_SMTP = 25, /* Simple Mail Transfer Protocol. */ + IPPORT_TIMESERVER = 37, /* Timeserver service. */ + IPPORT_NAMESERVER = 42, /* Domain Name Service. */ + IPPORT_WHOIS = 43, /* Internet Whois service. */ + IPPORT_MTP = 57, + + IPPORT_TFTP = 69, /* Trivial File Transfer Protocol. */ + IPPORT_RJE = 77, + IPPORT_FINGER = 79, /* Finger service. */ + IPPORT_TTYLINK = 87, + IPPORT_SUPDUP = 95, /* SUPDUP protocol. */ + + + IPPORT_EXECSERVER = 512, /* execd service. */ + IPPORT_LOGINSERVER = 513, /* rlogind service. */ + IPPORT_CMDSERVER = 514, + IPPORT_EFSSERVER = 520, + + /* UDP ports. */ + IPPORT_BIFFUDP = 512, + IPPORT_WHOSERVER = 513, + IPPORT_ROUTESERVER = 520, + + /* Ports less than this value are reserved for privileged processes. */ + IPPORT_RESERVED = 1024, + + /* Ports greater this value are reserved for (non-privileged) servers. */ + IPPORT_USERRESERVED = 5000 +}; + +/* Internet address. */ +struct in_addr +{ + in_addr_t s_addr; +}; + +/* Request struct for multicast socket ops */ + +struct ip_mreq +{ + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +}; + + +/* Structure describing an Internet (IP) socket address. */ +#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */ +struct sockaddr_in +{ + sa_family_t sin_family; /* Address family */ + in_port_t sin_port; /* Port number */ + struct in_addr sin_addr; /* Internet address */ + + /* Pad to size of `struct sockaddr'. */ + unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) + - sizeof(unsigned short int) - sizeof(struct in_addr)]; +}; +#define sin_zero __pad /* for BSD UNIX comp. -FvK */ + +/* + * Definitions of the bits in an Internet address integer. + * On subnets, host and network parts are found according + * to the subnet mask, not these masks. + */ +#define IN_CLASSA(a) ((((long int) (a)) & 0x80000000) == 0) +#define IN_CLASSA_NET 0xff000000 +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) +#define IN_CLASSA_MAX 128 + +#define IN_CLASSB(a) ((((long int) (a)) & 0xc0000000) == 0x80000000) +#define IN_CLASSB_NET 0xffff0000 +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) +#define IN_CLASSB_MAX 65536 + +#define IN_CLASSC(a) ((((long int) (a)) & 0xe0000000) == 0xc0000000) +#define IN_CLASSC_NET 0xffffff00 +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) + +#define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000) +#define IN_MULTICAST(a) IN_CLASSD(a) +#define IN_MULTICAST_NET 0xF0000000 + +#define IN_EXPERIMENTAL(a) ((((long int) (a)) & 0xe0000000) == 0xe0000000) +#define IN_BADCLASS(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000) + +/* Address to accept any incoming messages. */ +#define INADDR_ANY ((unsigned long int) 0x00000000) + +/* Address to send to all hosts. */ +#define INADDR_BROADCAST ((unsigned long int) 0xffffffff) + +/* Address indicating an error return. */ +#define INADDR_NONE 0xffffffff + +/* Network number for local host loopback. */ +#define IN_LOOPBACKNET 127 + +/* Address to loopback in software to local host. */ +#define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */ +#define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000) + +/* Defines for Multicast INADDR */ +#define INADDR_UNSPEC_GROUP 0xe0000000 /* 224.0.0.0 */ +#define INADDR_ALLHOSTS_GROUP 0xe0000001 /* 224.0.0.1 */ +#define INADDR_MAX_LOCAL_GROUP 0xe00000ff /* 224.0.0.255 */ + +#define INET_ADDRSTRLEN 16 + +/* <asm/byteorder.h> contains the htonl type stuff.. */ + +#include <asm/byteorder.h> + +/* Some random defines to make it easier in the kernel.. */ +#ifdef __KERNEL__ + +#define LOOPBACK(x) (((x) & htonl(0xff000000)) == htonl(0x7f000000)) +#define MULTICAST(x) (((x) & htonl(0xf0000000)) == htonl(0xe0000000)) + +#endif + +#ifdef AF_INET6 +#include <cygwin/in6.h> +#endif +#endif /* _CYGWIN_IN_H */ diff --git a/winsup/cygwin/include/cygwin/in6.h b/winsup/cygwin/include/cygwin/in6.h new file mode 100644 index 00000000000..ef73588f49c --- /dev/null +++ b/winsup/cygwin/include/cygwin/in6.h @@ -0,0 +1,119 @@ +/* cygwin/in6.h + + Copyright 2006 Red Hat, Inc. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +/* NOTE: This file is NOT for direct inclusion. Use netinet/in.h. */ + +#ifndef _CYGWIN_IN6_H +#define _CYGWIN_IN6_H + +#define INET6_ADDRSTRLEN 46 + +#define IN6_ARE_ADDR_EQUAL(a, b) \ + (((const uint32_t *)(a))[0] == ((const uint32_t *)(b))[0] \ + && ((const uint32_t *)(a))[1] == ((const uint32_t *)(b))[1] \ + && ((const uint32_t *)(a))[2] == ((const uint32_t *)(b))[2] \ + && ((const uint32_t *)(a))[3] == ((const uint32_t *)(b))[3]) + +#define IN6_IS_ADDR_UNSPECIFIED(addr) \ + (((const uint32_t *)(addr))[0] == 0 \ + && ((const uint32_t *)(addr))[1] == 0 \ + && ((const uint32_t *)(addr))[2] == 0 \ + && ((const uint32_t *)(addr))[3] == 0) + +#define IN6_IS_ADDR_LOOPBACK(addr) \ + (((const uint32_t *)(addr))[0] == 0 \ + && ((const uint32_t *)(addr))[1] == 0 \ + && ((const uint32_t *)(addr))[2] == 0 \ + && ((const uint32_t *)(addr))[3] == htonl (1)) + +#define IN6_IS_ADDR_MULTICAST(addr) (((const uint8_t *) (addr))[0] == 0xff) + +#define IN6_IS_ADDR_LINKLOCAL(addr) \ + ((((const uint16_t *)(addr))[0] & htons (0xffc0)) == htons (0xfe80)) + +#define IN6_IS_ADDR_SITELOCAL(addr) \ + ((((const uint16_t *)(addr))[0] & htons (0xffc0)) == htons (0xfec0)) + +#define IN6_IS_ADDR_V4MAPPED(addr) \ + (((const uint32_t *)(addr))[0] == 0 \ + && ((const uint32_t *)(addr))[1] == 0 \ + && ((const uint32_t *)(addr))[2] == htonl (0xffff)) + +#define IN6_IS_ADDR_V4COMPAT(addr) \ + (((const uint32_t *)(addr))[0] == 0 \ + && ((const uint32_t *)(addr))[1] == 0 \ + && ((const uint32_t *)(addr))[2] == 0 \ + && ntohl (((const uint32_t *)(addr))[3]) > 1) + +#define IN6_IS_ADDR_MC_NODELOCAL(addr) \ + (IN6_IS_ADDR_MULTICAST(addr) \ + && (((const uint8_t *)(addr))[1] & 0xf) == 0x1) + +#define IN6_IS_ADDR_MC_LINKLOCAL(addr) \ + (IN6_IS_ADDR_MULTICAST (addr) \ + && (((const uint8_t *)(addr))[1] & 0xf) == 0x2) + +#define IN6_IS_ADDR_MC_SITELOCAL(addr) \ + (IN6_IS_ADDR_MULTICAST(addr) \ + && (((const uint8_t *)(addr))[1] & 0xf) == 0x5) + +#define IN6_IS_ADDR_MC_ORGLOCAL(addr) \ + (IN6_IS_ADDR_MULTICAST(addr) \ + && (((const uint8_t *)(addr))[1] & 0xf) == 0x8) + +#define IN6_IS_ADDR_MC_GLOBAL(addr) \ + (IN6_IS_ADDR_MULTICAST(addr) \ + && (((const uint8_t *)(addr))[1] & 0xf) == 0xe) + +struct in6_addr +{ + union + { + uint8_t __s6_addr_u[16]; + uint16_t __s6_addr16[8]; + uint32_t __s6_addr32[4]; + } __u6; +#define s6_addr __u6.__s6_addr +#define s6_addr16 __u6.__s6_addr16 +#define s6_addr32 __u6.__s6_addr32 +}; + +struct ipv6_mreq +{ + struct in6_addr ipv6mr_multiaddr; + unsigned int ipv6mr_interface; +}; + +struct in6_pktinfo +{ + struct in6_addr ipi6_addr; + unsigned int ipi6_ifindex; +}; + +#ifdef __INSIDE_CYGWIN__ +typedef uint16_t in_port_t; +#endif + +struct sockaddr_in6 +{ + sa_family_t sin6_family; /* AF_INET6 */ + in_port_t sin6_port; /* Port number. */ + uint32_t sin6_flowinfo; /* Traffic class and flow inf. */ + struct in6_addr sin6_addr; /* IPv6 address. */ + uint32_t sin6_scope_id; /* Set of interfaces for a scope. */ +}; + +#define IN6ADDR_ANY_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } +#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } + +extern const struct in6_addr in6addr_any; +extern const struct in6_addr in6addr_loopback; + +#endif /* _CYGWIN_IN6_H */ diff --git a/winsup/cygwin/include/cygwin/socket.h b/winsup/cygwin/include/cygwin/socket.h new file mode 100644 index 00000000000..33aec8c6306 --- /dev/null +++ b/winsup/cygwin/include/cygwin/socket.h @@ -0,0 +1,277 @@ +/* cygwin/socket.h + + Copyright 1999, 2000, 2001, 2005 Red Hat, Inc. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifndef _CYGWIN_SOCKET_H +#define _CYGWIN_SOCKET_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <stdint.h> + +/* Not unsigned for backward compatibility. Keep #define for backward + compatibility. */ +#ifndef socklen_t +typedef int socklen_t; +#define socklen_t socklen_t +#endif + +typedef uint16_t sa_family_t; + +struct sockaddr { + sa_family_t sa_family; /* address family, AF_xxx */ + char sa_data[14]; /* 14 bytes of protocol address */ +}; + +/* Definition of sockaddr_storage according to SUSv3. */ +#define _SS_MAXSIZE 128 /* Maximum size. */ +#define _SS_ALIGNSIZE (sizeof (int64_t))/* Desired alignment. */ +#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof (sa_family_t)) +#define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof (sa_family_t) \ + + _SS_PAD1SIZE + _SS_ALIGNSIZE)) + +struct sockaddr_storage { + sa_family_t ss_family; + char _ss_pad1[_SS_PAD1SIZE]; + int64_t __ss_align; + char _ss_pad2[_SS_PAD2SIZE]; +}; + +#include <asm/socket.h> /* arch-dependent defines */ +#include <cygwin/sockios.h> /* the SIOCxxx I/O controls */ +#include <cygwin/uio.h> /* iovec support */ +#include <sys/types.h> + +struct ucred { + pid_t pid; + __uid32_t uid; + __gid32_t gid; +}; + +struct linger { + unsigned short l_onoff; /* Linger active */ + unsigned short l_linger; /* How long to linger for */ +}; + +struct msghdr +{ + void * msg_name; /* Socket name */ + socklen_t msg_namelen; /* Length of name */ + struct iovec * msg_iov; /* Data blocks */ + int msg_iovlen; /* Number of blocks */ + void * msg_control; /* Ancillary data */ + socklen_t msg_controllen; /* Ancillary data buffer length */ + int msg_flags; /* Received flags on recvmsg */ +}; + +struct cmsghdr +{ + socklen_t cmsg_len; /* Length of cmsghdr + data */ + int cmsg_level; /* Protocol */ + int cmsg_type; /* Protocol type */ +}; + +#define CMSG_ALIGN(len) \ + (((len) + sizeof (size_t) - 1) & ~(sizeof (size_t) - 1)) +#define CMSG_LEN(len) \ + (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) +#define CMSG_SPACE(len) \ + (CMSG_ALIGN (sizeof (struct cmsghdr)) + CMSG_ALIGN(len)) +#define CMSG_FIRSTHDR(mhdr) \ + ({ \ + struct msghdr *_m = (struct msghdr *) mhdr; \ + (unsigned) (_m)->msg_controllen >= sizeof (struct cmsghdr) \ + ? (struct cmsghdr *) (_m)->msg_control \ + : (struct cmsghdr *) NULL; \ + }) +#define CMSG_NXTHDR(mhdr,cmsg) \ + ({ \ + struct msghdr *_m = (struct msghdr *) mhdr; \ + struct cmsghdr *_c = (struct cmsghdr *) cmsg; \ + ((char *) _c + CMSG_SPACE (_c->cmsg_len) \ + > (char *) _m->msg_control + _m->msg_controllen) \ + ? (struct cmsghdr *) NULL \ + : (struct cmsghdr *) ((char *) _c + CMSG_ALIGN (_c->cmsg_len)); \ + }) +#define CMSG_DATA(cmsg) \ + ((unsigned char *) ((struct cmsghdr *)(cmsg) + 1)) + +/* "Socket"-level control message types: */ +#define SCM_RIGHTS 0x01 /* access rights (array of int) */ + +#ifdef __INSIDE_CYGWIN__ +/* Definition of struct msghdr up to release 1.5.18 */ +struct OLD_msghdr +{ + void * msg_name; /* Socket name */ + int msg_namelen; /* Length of name */ + struct iovec * msg_iov; /* Data blocks */ + int msg_iovlen; /* Number of blocks */ + void * msg_accrights; /* Per protocol magic */ + /* (eg BSD descriptor passing) */ + int msg_accrightslen; /* Length of rights list */ +}; +#endif + +/* Socket types. */ +#define SOCK_STREAM 1 /* stream (connection) socket */ +#define SOCK_DGRAM 2 /* datagram (conn.less) socket */ +#define SOCK_RAW 3 /* raw socket */ +#define SOCK_RDM 4 /* reliably-delivered message */ +#define SOCK_SEQPACKET 5 /* sequential packet socket */ + +/* Supported address families. */ +/* + * Address families. + */ +#define AF_UNSPEC 0 /* unspecified */ +#define AF_UNIX 1 /* local to host (pipes, portals) */ +#define AF_LOCAL 1 /* POSIX name for AF_UNIX */ +#define AF_INET 2 /* internetwork: UDP, TCP, etc. */ +#define AF_IMPLINK 3 /* arpanet imp addresses */ +#define AF_PUP 4 /* pup protocols: e.g. BSP */ +#define AF_CHAOS 5 /* mit CHAOS protocols */ +#define AF_NS 6 /* XEROX NS protocols */ +#define AF_ISO 7 /* ISO protocols */ +#define AF_OSI AF_ISO /* OSI is ISO */ +#define AF_ECMA 8 /* european computer manufacturers */ +#define AF_DATAKIT 9 /* datakit protocols */ +#define AF_CCITT 10 /* CCITT protocols, X.25 etc */ +#define AF_SNA 11 /* IBM SNA */ +#define AF_DECnet 12 /* DECnet */ +#define AF_DLI 13 /* Direct data link interface */ +#define AF_LAT 14 /* LAT */ +#define AF_HYLINK 15 /* NSC Hyperchannel */ +#define AF_APPLETALK 16 /* AppleTalk */ +#define AF_NETBIOS 17 /* NetBios-style addresses */ +#define AF_INET6 23 /* IP version 6 */ + +#define AF_MAX 32 +/* + * Protocol families, same as address families for now. + */ +#define PF_UNSPEC AF_UNSPEC +#define PF_UNIX AF_UNIX +#define PF_LOCAL AF_LOCAL +#define PF_INET AF_INET +#define PF_IMPLINK AF_IMPLINK +#define PF_PUP AF_PUP +#define PF_CHAOS AF_CHAOS +#define PF_NS AF_NS +#define PF_ISO AF_ISO +#define PF_OSI AF_OSI +#define PF_ECMA AF_ECMA +#define PF_DATAKIT AF_DATAKIT +#define PF_CCITT AF_CCITT +#define PF_SNA AF_SNA +#define PF_DECnet AF_DECnet +#define PF_DLI AF_DLI +#define PF_LAT AF_LAT +#define PF_HYLINK AF_HYLINK +#define PF_APPLETALK AF_APPLETALK +#define PF_NETBIOS AF_NETBIOS +#define PF_INET6 AF_INET6 + +#define PF_MAX AF_MAX + +/* Maximum queue length specificable by listen. */ +#define SOMAXCONN 0x7fffffff + +/* Flags we can use with send/ and recv. */ +#define MSG_OOB 0x1 /* process out-of-band data */ +#define MSG_PEEK 0x2 /* peek at incoming message */ +#define MSG_DONTROUTE 0x4 /* send without using routing tables */ +#define MSG_WINMASK 0x7 /* flags understood by WinSock calls */ +#define MSG_NOSIGNAL 0x20 /* Don't raise SIGPIPE */ +#define MSG_TRUNC 0x0100 /* Normal data truncated */ +#define MSG_CTRUNC 0x0200 /* Control data truncated */ + +/* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */ +#define SOL_IP 0 +#define SOL_IPX 256 +#define SOL_AX25 257 +#define SOL_ATALK 258 +#define SOL_NETROM 259 +#define SOL_TCP 6 +#define SOL_UDP 17 + +/* IP options */ +#ifndef IPTOS_LOWDELAY +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#endif + +/* These need to appear somewhere around here */ +#define IP_DEFAULT_MULTICAST_TTL 1 +#define IP_DEFAULT_MULTICAST_LOOP 1 +#define IP_MAX_MEMBERSHIPS 20 + +/* IP options for use with getsockopt/setsockopt */ +#define IP_OPTIONS 1 +#define IP_HDRINCL 2 +#define IP_TOS 3 +#define IP_TTL 4 +#define IP_MULTICAST_IF 9 +#define IP_MULTICAST_TTL 10 +#define IP_MULTICAST_LOOP 11 +#define IP_ADD_MEMBERSHIP 12 +#define IP_DROP_MEMBERSHIP 13 +#define IP_DONTFRAGMENT 14 +#define IP_ADD_SOURCE_MEMBERSHIP 15 +#define IP_DROP_SOURCE_MEMBERSHIP 16 +#define IP_BLOCK_SOURCE 17 +#define IP_UNBLOCK_SOURCE 18 +#define IP_PKTINFO 19 + +/* IPv6 options for use with getsockopt/setsockopt */ +#define IPV6_UNICAST_HOPS 4 +#define IPV6_MULTICAST_IF 9 +#define IPV6_MULTICAST_HOPS 10 +#define IPV6_MULTICAST_LOOP 11 +#define IPV6_ADD_MEMBERSHIP 12 +#define IPV6_DROP_MEMBERSHIP 13 +#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP +#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP +#define IPV6_PKTINFO 19 + +/* Old WinSock1 values, needed internally */ +#ifdef __INSIDE_CYGWIN__ +#define _WS1_IP_OPTIONS 1 +#define _WS1_IP_MULTICAST_IF 2 +#define _WS1_IP_MULTICAST_TTL 3 +#define _WS1_IP_MULTICAST_LOOP 4 +#define _WS1_IP_ADD_MEMBERSHIP 5 +#define _WS1_IP_DROP_MEMBERSHIP 6 +#define _WS1_IP_TTL 7 +#define _WS1_IP_TOS 8 +#define _WS1_IP_DONTFRAGMENT 9 +#endif + +/* IPX options */ +#define IPX_TYPE 1 + +/* TCP options - this way around because someone left a set in the c library includes */ +#ifndef TCP_NODELAY +#define TCP_NODELAY 0x0001 +#define TCP_MAXSEG 2 +#endif + +/* The various priorities. */ +#define SOPRI_INTERACTIVE 0 +#define SOPRI_NORMAL 1 +#define SOPRI_BACKGROUND 2 + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ + +#endif /* _CYGWIN_SOCKET_H */ diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h new file mode 100644 index 00000000000..ab2de7af3dd --- /dev/null +++ b/winsup/cygwin/include/cygwin/version.h @@ -0,0 +1,367 @@ +/* version.h -- Cygwin version numbers and accompanying documentation. + + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, + 2005, 2006 Red Hat, Inc. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +/* Cygwin versioning is relatively complicated because of its status + as a shared library. Let's start with how versioning used to be done. + + Historical versioning in Cygwin 16.0 to 19.5: + + In the olden days of Cygwin, we had a dll major and minor version + and a registry version. The major number started at 16 because the + "b15" GNU-Win32 release of the compiler tools was out when this + scheme was started. We incremented the DLL name frequently (for + every official release) and towards the end of this period every + release used a different shared memory area to prevent DLLs from + interfering with each other (embedding a build timestamp into the + name of the shared memory area). This turned out to be a Bad Idea + (tm) because people needed to mingle separate releases and have + them work together more than we thought they would. This was + especially problematic when tty info needed to be retained when an + old Cygwin executable executed a newer one. + + In the old scheme, we incremented the major number whenever a + change to the dll invalidated existing executables. This can + happen for a number of reasons, including when functions are + removed from the export list of the dll. The minor number was + incremented when a change was made that we wanted to record, but + that didn't invalidate existing executables. Both numbers were + recorded in the executable and in the dll. + + In October 1998 (starting with Cygwin 19.6), we started a new method + of Cygwin versioning: */ + + /* The DLL major and minor numbers correspond to the "version of + the Cygwin shared library". This version is used to track important + changes to the DLL and is mainly informative in nature. */ + +#define CYGWIN_VERSION_DLL_MAJOR 1005 +#define CYGWIN_VERSION_DLL_MINOR 21 + + /* Major numbers before CYGWIN_VERSION_DLL_EPOCH are + incompatible. */ + +#define CYGWIN_VERSION_DLL_EPOCH 19 + + /* CYGWIN_VERSION_DLL_COMBINED gives us a single number + representing the combined DLL major and minor numbers. */ + + /* WATCH OUT FOR OCTAL! Don't use, say, "00020" for 0.20 */ + +#define CYGWIN_VERSION_DLL_MAKE_COMBINED(maj, min) (((maj) * 1000) + min) +#define CYGWIN_VERSION_DLL_COMBINED \ + CYGWIN_VERSION_DLL_MAKE_COMBINED (CYGWIN_VERSION_DLL_MAJOR, CYGWIN_VERSION_DLL_MINOR) + + /* Every version of cygwin <= this uses an old, incorrect method + to determine signal masks. */ + +#define CYGWIN_VERSION_DLL_BAD_SIGNAL_MASK 19005 + +#define CYGWIN_VERSION_USER_API_VERSION_COMBINED \ + CYGWIN_VERSION_DLL_MAKE_COMBINED (user_data->api_major, user_data->api_minor) + + /* API versions <= this had a termios structure whose members were + too small to accomodate modern settings. */ +#define CYGWIN_VERSION_DLL_OLD_TERMIOS 5 +#define CYGWIN_VERSION_DLL_IS_OLD_TERMIOS \ + (CYGWIN_VERSION_USER_API_VERSION_COMBINED <= CYGWIN_VERSION_DLL_OLD_TERMIOS) + +#define CYGWIN_VERSION_DLL_MALLOC_ENV 28 + /* Old APIs had getc/putc macros that conflict with new CR/LF + handling in the stdio buffers */ +#define CYGWIN_VERSION_OLD_STDIO_CRLF_HANDLING \ + (CYGWIN_VERSION_USER_API_VERSION_COMBINED <= 20) + +#define CYGWIN_VERSION_CHECK_FOR_S_IEXEC \ + (CYGWIN_VERSION_USER_API_VERSION_COMBINED >= 36) + +#define CYGWIN_VERSION_CHECK_FOR_OLD_O_NONBLOCK \ + (CYGWIN_VERSION_USER_API_VERSION_COMBINED <= 28) + +#define CYGWIN_VERSION_CHECK_FOR_USING_BIG_TYPES \ + (CYGWIN_VERSION_USER_API_VERSION_COMBINED >= 79) + +#define CYGWIN_VERSION_CHECK_FOR_USING_ANCIENT_MSGHDR \ + (CYGWIN_VERSION_USER_API_VERSION_COMBINED <= 138) + +#define CYGWIN_VERSION_CHECK_FOR_USING_WINSOCK1_VALUES \ + (CYGWIN_VERSION_USER_API_VERSION_COMBINED <= 138) + + /* API_MAJOR 0.0: Initial version. API_MINOR changes: + 1: Export cygwin32_ calls as cygwin_ as well. + 2: Export j1, jn, y1, yn. + 3: Export dll_noncygwin_dllcrt0. + 4: New socket ioctls, revamped ifconf support. + 5: Thread support/exports. + 6: Change in termios handling. + 7: Export scandir and alphasort. + 8: Export _ctype_, _sys_errlist, _sys_nerr. + 9: Mount-related changes, new cygwin_umount export. + Raw device support (tape, floppies). + 10: Fast math routine support added. + 11: Export seekdir, telldir. + 12: Export pthread_join, pthread_detach. + 13: Export math funcs gamma and friends, also _j0, _j1, etc. + 14: Export snprintf and vnsprintf. + 15: Export glob + 16: Export cygwin_stackdump + 17: Export fast math stuff + 18: Stop exporting _strace_wm + 19: Export fchown, lchown, lacl + 20: regsub, inet_network + 21: incompatible change to stdio cr/lf and buffering + 22: Export cygwin_logon_user, cygwin_set_impersonation_token. + geteuid, getegid return effective uid/gid. + getuid, getgid return real uid/gid. + seteuid, setegid set only effective uid/gid. + setuid, setgid set effective and real uid/gid. + 23: Export new dll_crt0 interface and cygwin_user_data for use + with crt0 startup code. + 24: Export poll and _poll. + 25: Export getmode and _getmode. + 26: CW_GET_CYGDRIVE_PREFIXES addition to external.cc + 27: CW_GETPINFO_FULL addition to external.cc + 28: Accidentally bumped by cgf + 29: Export hstrerror + 30: CW_GET_CYGDRIVE_INFO addition to external.cc + 31: Export inet_aton + 32: Export getrlimit/setrlimit + 33: Export setlogmask + 34: Separated out mount table + 35: Export drand48, erand48, jrand48, lcong48, lrand48, + mrand48, nrand48, seed48, and srand48. + 36: Added _cygwin_S_IEXEC, et al + 37: [f]pathconv support _PC_POSIX_PERMISSIONS and _PC_POSIX_SECURITY + 38: vscanf, vscanf_r, and random pthread functions + 39: asctime_r, ctime_r, gmtime_r, localtime_r + 40: fchdir + 41: __signgam + 42: sys_errlist, sys_nerr + 43: sigsetjmp, siglongjmp fixed + 44: Export dirfd + 45: perprocess change, gamma_r, gammaf_r, lgamma_r, lgammaf_r + 46: Remove cygwin_getshared + 47: Report EOTWarningZoneSize in struct mtget. + 48: Export "posix" regex functions + 49: Export setutent, endutent, utmpname, getutent, getutid, getutline. + 50: Export fnmatch. + 51: Export recvmsg, sendmsg. + 52: Export strptime + 53: Export strlcat, strlcpy. + 54: Export __fpclassifyd, __fpclassifyf, __signbitd, __signbitf. + 55: Export fcloseall, fcloseall_r. + 56: Make ntsec on by default. + 57: Export setgroups. + 58: Export memalign, valloc, malloc_trim, malloc_usable_size, mallopt, + malloc_stats + 59: getsid + 60: MSG_NOSIGNAL + 61: Export getc_unlocked, getchar_unlocked, putc_unlocked, + putchar_unlocked + 62: Erroneously bumped + 63: Export pututline + 64: Export fseeko, ftello + 65: Export siginterrupt + 66: Export nl_langinfo + 67: Export pthread_getsequence_np + 68: Export netdb stuff + 69: Export strtof + 70: Export asprintf, _asprintf_r, vasprintf, _vasprintf_r + 71: Export strerror_r + 72: Export nanosleep + 73: Export setreuid32, setreuid, setregid32, setregid + 74: Export _strtold a64l hcreate hcreate_r hdestroy hdestroy_r hsearch + hsearch_r isblank iswalnum iswalpha iswblank iswcntrl iswctype + iswdigit iswgraph iswlower iswprint iswpunct iswspace iswupper + iswxdigit l64a mbrlen mbrtowc mbsinit mbsrtowcs mempcpy + on_exit setbuffer setlinebuf strndup strnlen tdelete tdestroy + tfind towctrans towlower towupper tsearch twalk wcrtomb wcscat + wcschr wcscpy wcscspn wcslcat wcslcpy wcsncat wcsncmp wcsncpy + wcspbrk wcsrchr wcsrtombs wcsspn wcsstr wctob wctob wctrans + wctype wmemchr wmemcmp wmemcpy wmemmove wmemset + 75: Export exp2 exp2f fdim fdimf fma fmaf fmax fmaxf fmin fminf lrint + lrintf lround lroundf nearbyint nearbyintf remquo remquof + round roundf scalbln scalblnf sincos sincosf tgamma tgammaf + truncf + 76: mallinfo + 77: thread-safe exit/at_exit + 78: Use stat and fstat rather than _stat, and _fstat. + Export btowc and trunc. + 79: Export acl32 aclcheck32 aclfrommode32 aclfrompbits32 aclfromtext32 + aclsort32 acltomode32 acltopbits32 acltotext32 facl32 + fgetpos64 fopen64 freopen64 fseeko64 fsetpos64 ftello64 + _open64 _lseek64 _fstat64 _stat64 mknod32 + 80: Export pthread_rwlock stuff + 81: CW_CHECK_NTSEC addition to external.cc + 82: Export wcscoll wcswidth wcwidth + 83: Export gethostid + 84: Pty open allocates invisible console. 64 bit interface + 85: Export new 32/64 functions from API 0.79 only with leading + underscore. No problems with backward compatibility since no + official release has been made so far. This change removes + exported symbols like fopen64, which might confuse configure. + 86: Export ftok + 87: Export vsyslog + 88: Export _getreent + 89: Export __mempcpy + 90: Export _fopen64 + 91: Export argz_add argz_add_sep argz_append argz_count argz_create + argz_create_sep argz_delete argz_extract argz_insert + argz_next argz_replace argz_stringify envz_add envz_entry + envz_get envz_merge envz_remove envz_strip + 92: Export getusershell, setusershell, endusershell + 93: Export daemon, forkpty, openpty, iruserok, ruserok, login_tty, + openpty, forkpty, revoke, logwtmp, updwtmp + 94: Export getopt, getopt_long, optarg, opterr, optind, optopt, + optreset, __check_rhosts_file, __rcmd_errstr. + 95: Export shmat, shmctl, shmdt, shmget. + 96: CW_GET_ERRNO_FROM_WINERROR addition to external.cc + 97: Export sem_open, sem_close, sem_timedwait, sem_getvalue. + 98: Export _tmpfile64. + 99: CW_GET_POSIX_SECURITY_ATTRIBUTE addition to external.cc. + 100: CW_GET_SHMLBA addition to external.cc. + 101: Export err, errx, verr, verrx, warn, warnx, vwarn, vwarnx. + 102: CW_GET_UID_FROM_SID and CW_GET_GID_FROM_SID addition to external.cc. + 103: Export getprogname, setprogname. + 104: Export msgctl, msgget, msgrcv, msgsnd, semctl, semget, semop. + 105: Export sigwait. + 106: Export flock. + 107: Export fcntl64. + 108: Remove unused (hopefully) reent_data export. + 109: Oh well. Someone uses reent_data. + 110: Export clock_gettime, sigwaitinfo, timer_create, timer_delete, + timer_settime + 111: Export sigqueue, sighold. + 112: Redefine some mtget fields. + 113: Again redefine some mtget fields. Use mt_fileno and mt_blkno as + on Linux. + 114: Export rand_r, ttyname_r. + 115: Export flockfile, ftrylockfile, funlockfile, getgrgid_r, getgrnam_r, + getlogin_r. + 116: Export atoll. + 117: Export utmpx functions, Return utmp * from pututent. + 118: Export getpriority, setpriority. + 119: Export fdatasync. + 120: Export basename, dirname. + 122: Export statvfs, fstatvfs. + 123: Export utmpxname. + 124: Add MAP_AUTOGROW flag to mmap. + 125: LD_PRELOAD/CW_HOOK available. + 126: Export lsearch, lfind, timer_gettime. + 127: Export sigrelese. + 128: Export pselect. + 129: Export mkdtemp. + 130: Export strtoimax, strtoumax, llabs, imaxabs, lldiv, imaxdiv. + 131: Export inet_ntop, inet_pton. + 132: Add GLOB_LIMIT flag to glob. + 133: Export __getline, __getdelim. + 134: Export getline, getdelim. + 135: Export pread, pwrite + 136: Add TIOCMBIS/TIOCMBIC ioctl codes. + 137: fts_children, fts_close, fts_get_clientptr, fts_get_stream, + fts_open, fts_read, fts_set, fts_set_clientptr, ftw, nftw. + 138: Export readdir_r. + 139: Start using POSIX definition of struct msghdr and WinSock2 + IPPROTO_IP values. + 140: Export mlock, munlock. + 141: Export futimes, lutimes. + 142: Export memmem + 143: Export clock_getres, clock_setres + 144: Export timelocal, timegm. + 145: Add MAP_NORESERVE flag to mmap. + 146: Change SI_USER definition. FIXME: Need to develop compatibility + macro for this? + 147: Eliminate problematic d_ino from dirent structure. unsetenv now + returns int, as per linux. + 148: Add open(2) flags O_SYNC, O_RSYNC, O_DSYNC and O_DIRECT. + 149: Add open(2) flag O_NOFOLLOW. + 150: Export getsubopt. + 151: Export __opendir_with_d_ino + 152: Revert to having d_ino in dirent unconditionally. + 153: Export updwtmpx, Implement CW_SETUP_WINENV. + 154: Export sigset, sigignore. + 155: Export __isinff, __isinfd, __isnanf, __isnand. + 156: Export __srbuf_r, __swget_r. + 157: Export gai_strerror, getaddrinfo, getnameinfo, freeaddrinfo, + in6addr_any, in6addr_loopback. + */ + + /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ + +#define CYGWIN_VERSION_API_MAJOR 0 +#define CYGWIN_VERSION_API_MINOR 157 + + /* There is also a compatibity version number associated with the + shared memory regions. It is incremented when incompatible + changes are made to the shared memory region *or* to any named + shared mutexes, semaphores, etc. The arbitrary starting + version was 0 (cygwin release 98r2). + Bump to 4 since this hasn't been rigorously updated in a + while. */ + +#define CYGWIN_VERSION_SHARED_DATA 4 + + /* An identifier used in the names used to create shared objects. + The full names include the CYGWIN_VERSION_SHARED_DATA version + as well as this identifier. */ + +#define CYGWIN_VERSION_DLL_IDENTIFIER "cygwin1" + + /* The Cygwin mount table interface in the Win32 registry also + has a version number associated with it in case that is + changed in a non-backwards compatible fashion. Increment this + version number whenever incompatible changes in mount table + registry usage are made. + + 1: Original number version. + 2: New mount registry layout, system-wide mount accessibility. + */ + +#define CYGWIN_VERSION_MOUNT_REGISTRY 2 + + /* Identifiers used in the Win32 registry. */ + +#define CYGWIN_INFO_CYGNUS_REGISTRY_NAME "Cygnus Solutions" +#define CYGWIN_INFO_CYGWIN_REGISTRY_NAME "Cygwin" +#define CYGWIN_INFO_PROGRAM_OPTIONS_NAME "Program Options" +#define CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME "mounts v2" +#define CYGWIN_INFO_CYGDRIVE_FLAGS "cygdrive flags" +#define CYGWIN_INFO_CYGDRIVE_PREFIX "cygdrive prefix" +#define CYGWIN_INFO_CYGDRIVE_DEFAULT_PREFIX "/cygdrive" + + /* In addition to the above version number strings, the build + process adds some strings that may be useful in + debugging/identifying a particular Cygwin DLL: + + The mkvers.sh script at the top level produces a .cc file + which initializes a cygwin_version structure based on the + above version information and creates a string table for + grepping via "fgrep '%%%' cygwinwhatever.dll" if you are + using GNU grep. Otherwise you may want to do a + "strings cygwinwhatever.dll | fgrep '%%%'" instead. + + This will produce output such as: + + %%% Cygwin dll_identifier: cygwin + %%% Cygwin api_major: 0 + %%% Cygwin api_minor: 0 + %%% Cygwin dll_major: 19 + %%% Cygwin dll_minor: 6 + %%% Cygwin shared_data: 1 + %%% Cygwin registry: b15 + %%% Cygwin build date: Wed Oct 14 16:26:51 EDT 1998 + %%% Cygwin shared id: cygwinS1 + + This information can also be obtained through a call to + cygwin_internal (CW_GETVERSIONINFO). + */ + +#define CYGWIN_VERSION_MAGIC(a, b) ((unsigned) ((((unsigned short) a) << 16) | (unsigned short) b)) +#define CYGWIN_VERSION_MAGIC_VERSION(a) ((unsigned) ((unsigned)a & 0xffff)) diff --git a/winsup/cygwin/include/netdb.h b/winsup/cygwin/include/netdb.h new file mode 100644 index 00000000000..89bb1e7c26e --- /dev/null +++ b/winsup/cygwin/include/netdb.h @@ -0,0 +1,227 @@ +/* Original linux netdb.h merged with winsock.h types */ + +/*- + * Copyright (c) 1980, 1983, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)netdb.h 8.1 (Berkeley) 6/2/93 + * netdb.h,v 1.1.1.1 1995/02/18 05:34:07 hjl Exp + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#ifndef _NETDB_H_ +#define _NETDB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <cygwin/socket.h> + +/* + * Structures returned by network data base library. All addresses are + * supplied in host order, and returned in network order (suitable for + * use in system calls). + */ + + /* Different from the linux versions - note the shorts.. */ +struct hostent { + const char *h_name; /* official name of host */ + char **h_aliases; /* alias list */ + short h_addrtype; /* host address type */ + short h_length; /* length of address */ + char **h_addr_list; /* list of addresses from name server */ +#define h_addr h_addr_list[0] /* address, for backward compatiblity */ +}; + +/* + * Assumption here is that a network number + * fits in an unsigned long -- probably a poor one. + */ + +struct netent { + char *n_name; /* official name of net */ + char **n_aliases; /* alias list */ + short n_addrtype; /* net address type */ + uint32_t n_net; /* network # */ +}; + +struct servent { + char *s_name; /* official service name */ + char **s_aliases; /* alias list */ + short s_port; /* port # */ + char *s_proto; /* protocol to use */ +}; + +struct protoent +{ + char *p_name; /* official protocol name */ + char **p_aliases; /* alias list */ + short p_proto; /* protocol # */ +}; + +struct rpcent { + char *r_name; /* name of server for this rpc program */ + char **r_aliases; /* alias list */ + int r_number; /* rpc program number */ +}; + +struct addrinfo { + int ai_flags; /* input flags */ + int ai_family; /* address family of socket */ + int ai_socktype; /* socket type */ + int ai_protocol; /* ai_protocol */ + socklen_t ai_addrlen; /* length of socket address */ + char *ai_canonname; /* canonical name of service location */ + struct sockaddr *ai_addr; /* socket address of socket */ + struct addrinfo *ai_next; /* pointer to next in list */ +}; + +/* + * Error return codes from gethostbyname() and gethostbyaddr() + * (left in extern int h_errno). + */ + +#ifdef __INSIDE_CYGWIN_NET__ +extern int h_errno; +#else +extern __declspec(dllimport) int h_errno; +#endif + +#define NETDB_INTERNAL -1 /* see errno */ +#define NETDB_SUCCESS 0 /* no problem */ +#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */ +#define TRY_AGAIN 2 /* Non-Authoritive Host not found, or SERVERFAIL */ +#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ +#define NO_DATA 4 /* Valid name, no data record of requested type */ +#define NO_ADDRESS NO_DATA /* no address, look for MX record */ + +#define AI_PASSIVE 1 +#define AI_CANONNAME 2 +#define AI_NUMERICHOST 4 +/* + * These are not available in the WinSock implementation. It wouldn't make + * sense to support them in the ipv4 only case, so we drop them entirely. + * We can define them if we run into problems but they are non-functional, so... + */ +#if 0 +#define AI_V4MAPPED 16 +#define AI_ALL 32 +#define AI_ADDRCONFIG 64 +#endif + +#define NI_NOFQDN 1 +#define NI_NUMERICHOST 2 +#define NI_NAMEREQD 4 +#define NI_NUMERICSERV 8 +#define NI_DGRAM 16 + +#define NI_MAXHOST 1025 +#define NI_MAXSERV 32 + +#define EAI_ADDRFAMILY 1 +#define EAI_AGAIN 2 +#define EAI_BADFLAGS 3 +#define EAI_FAIL 4 +#define EAI_FAMILY 5 +#define EAI_MEMORY 6 +#define EAI_NODATA 7 +#define EAI_NONAME 8 +#define EAI_SERVICE 9 +#define EAI_SOCKTYPE 10 +#define EAI_SYSTEM 11 +#define EAI_BADHINTS 12 +#define EAI_PROTOCOL 13 + +#define EAI_MAX 14 + +#ifndef __INSIDE_CYGWIN_NET__ +void endhostent (void); +void endnetent (void); +void endprotoent (void); +void endservent (void); +void endrpcent (void); +struct hostent *gethostbyaddr (const char *, int, int); +struct hostent *gethostbyname (const char *); +struct hostent *gethostent (void); +struct netent *getnetbyaddr (long, int); /* u_long? */ +struct netent *getnetbyname (const char *); +struct netent *getnetent (void); +struct protoent *getprotobyname (const char *); +struct protoent *getprotobynumber (int); +struct protoent *getprotoent (void); +struct servent *getservbyname (const char *, const char *); +struct servent *getservbyport (int, const char *); +struct servent *getservent (void); +struct rpcent *getrpcent (void); +struct rpcent *getrpcbyname (const char *); +struct rpcent *getrpcbynumber (int); +const char *hstrerror (int); +void herror (const char *); +void sethostent (int); +void setnetent (int); +void setprotoent (int); +void setservent (int); +void setrpcent (int); +void freeaddrinfo (struct addrinfo *); +const char *gai_strerror (int); +int getaddrinfo (const char *, const char *, + const struct addrinfo *, struct addrinfo **); +int getnameinfo (const struct sockaddr *, socklen_t, char *, + socklen_t, char *, socklen_t, int); +#endif + +#ifdef __cplusplus +}; +#endif + +#endif /* !_NETDB_H_ */ + diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc new file mode 100644 index 00000000000..6391aee8500 --- /dev/null +++ b/winsup/cygwin/net.cc @@ -0,0 +1,3629 @@ +/* net.cc: network-related routines. + + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, + 2005, 2006 Red Hat, Inc. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +/* #define DEBUG_NEST_ON 1 */ + +#define __INSIDE_CYGWIN_NET__ + +#include "winsup.h" +#include <ctype.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <syslog.h> + +#include <stdlib.h> +#define gethostname cygwin_gethostname +#include <unistd.h> +#undef gethostname +#include <netdb.h> +#define USE_SYS_TYPES_FD_SET +#include <winsock2.h> +#include <iphlpapi.h> +#include <assert.h> +#include "cygerrno.h" +#include "security.h" +#include "cygwin/version.h" +#include "perprocess.h" +#include "path.h" +#include "fhandler.h" +#include "dtable.h" +#include "cygheap.h" +#include "sigproc.h" +#include "pinfo.h" +#include "registry.h" +#include "cygtls.h" +#include "cygwin/in6.h" + +extern "C" +{ + int h_errno; + + int __stdcall rcmd (char **ahost, unsigned short inport, char *locuser, + char *remuser, char *cmd, SOCKET * fd2p); + int sscanf (const char *, const char *, ...); +} /* End of "C" section */ + +const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; +const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; + +static fhandler_socket * +get (const int fd) +{ + cygheap_fdget cfd (fd); + + if (cfd < 0) + return 0; + + fhandler_socket *const fh = cfd->is_socket (); + + if (!fh) + set_errno (ENOTSOCK); + + return fh; +} + +/* htonl: standards? */ +extern "C" unsigned long int +htonl (unsigned long int x) +{ + return ((((x & 0x000000ffU) << 24) | + ((x & 0x0000ff00U) << 8) | + ((x & 0x00ff0000U) >> 8) | + ((x & 0xff000000U) >> 24))); +} + +/* ntohl: standards? */ +extern "C" unsigned long int +ntohl (unsigned long int x) +{ + return htonl (x); +} + +/* htons: standards? */ +extern "C" unsigned short +htons (unsigned short x) +{ + return ((((x & 0x000000ffU) << 8) | + ((x & 0x0000ff00U) >> 8))); +} + +/* ntohs: standards? */ +extern "C" unsigned short +ntohs (unsigned short x) +{ + return htons (x); +} + +/* exported as inet_ntoa: BSD 4.3 */ +extern "C" char * +cygwin_inet_ntoa (struct in_addr in) +{ + char *res = inet_ntoa (in); + + if (_my_tls.locals.ntoa_buf) + { + free (_my_tls.locals.ntoa_buf); + _my_tls.locals.ntoa_buf = NULL; + } + if (res) + _my_tls.locals.ntoa_buf = strdup (res); + return _my_tls.locals.ntoa_buf; +} + +/* exported as inet_addr: BSD 4.3 */ +extern "C" unsigned long +cygwin_inet_addr (const char *cp) +{ + myfault efault; + if (efault.faulted (EFAULT)) + return INADDR_NONE; + unsigned long res = inet_addr (cp); + + return res; +} + +/* exported as inet_aton: BSD 4.3 + inet_aton is not exported by wsock32 and ws2_32, + so it has to be implemented here. */ +extern "C" int +cygwin_inet_aton (const char *cp, struct in_addr *inp) +{ + myfault efault; + if (efault.faulted (EFAULT)) + return 0; + + unsigned long res = inet_addr (cp); + + if (res == INADDR_NONE && strcmp (cp, "255.255.255.255")) + return 0; + if (inp) + inp->s_addr = res; + return 1; +} + +extern "C" unsigned int +cygwin_inet_network (const char *cp) +{ + myfault efault; + if (efault.faulted (EFAULT)) + return INADDR_NONE; + return ntohl (inet_addr (cp)); +} + +/* inet_netof is in the standard BSD sockets library. It is useless + for modern networks, since it assumes network values which are no + longer meaningful, but some existing code calls it. */ + +extern "C" unsigned long +inet_netof (struct in_addr in) +{ + unsigned long i, res; + + i = ntohl (in.s_addr); + if (IN_CLASSA (i)) + res = (i & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT; + else if (IN_CLASSB (i)) + res = (i & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT; + else + res = (i & IN_CLASSC_NET) >> IN_CLASSC_NSHIFT; + + + return res; +} + +/* inet_makeaddr is in the standard BSD sockets library. It is + useless for modern networks, since it assumes network values which + are no longer meaningful, but some existing code calls it. */ + +extern "C" struct in_addr +inet_makeaddr (int net, int lna) +{ + unsigned long i; + struct in_addr in; + + if (net < IN_CLASSA_MAX) + i = (net << IN_CLASSA_NSHIFT) | (lna & IN_CLASSA_HOST); + else if (net < IN_CLASSB_MAX) + i = (net << IN_CLASSB_NSHIFT) | (lna & IN_CLASSB_HOST); + else if (net < 0x1000000) + i = (net << IN_CLASSC_NSHIFT) | (lna & IN_CLASSC_HOST); + else + i = net | lna; + + in.s_addr = htonl (i); + + + return in; +} + +struct tl +{ + int w; + const char *s; + int e; +}; + +static NO_COPY struct tl errmap[] = { + {WSAEINTR, "WSAEINTR", EINTR}, + {WSAEWOULDBLOCK, "WSAEWOULDBLOCK", EWOULDBLOCK}, + {WSAEINPROGRESS, "WSAEINPROGRESS", EINPROGRESS}, + {WSAEALREADY, "WSAEALREADY", EALREADY}, + {WSAENOTSOCK, "WSAENOTSOCK", ENOTSOCK}, + {WSAEDESTADDRREQ, "WSAEDESTADDRREQ", EDESTADDRREQ}, + {WSAEMSGSIZE, "WSAEMSGSIZE", EMSGSIZE}, + {WSAEPROTOTYPE, "WSAEPROTOTYPE", EPROTOTYPE}, + {WSAENOPROTOOPT, "WSAENOPROTOOPT", ENOPROTOOPT}, + {WSAEPROTONOSUPPORT, "WSAEPROTONOSUPPORT", EPROTONOSUPPORT}, + {WSAESOCKTNOSUPPORT, "WSAESOCKTNOSUPPORT", ESOCKTNOSUPPORT}, + {WSAEOPNOTSUPP, "WSAEOPNOTSUPP", EOPNOTSUPP}, + {WSAEPFNOSUPPORT, "WSAEPFNOSUPPORT", EPFNOSUPPORT}, + {WSAEAFNOSUPPORT, "WSAEAFNOSUPPORT", EAFNOSUPPORT}, + {WSAEADDRINUSE, "WSAEADDRINUSE", EADDRINUSE}, + {WSAEADDRNOTAVAIL, "WSAEADDRNOTAVAIL", EADDRNOTAVAIL}, + {WSAENETDOWN, "WSAENETDOWN", ENETDOWN}, + {WSAENETUNREACH, "WSAENETUNREACH", ENETUNREACH}, + {WSAENETRESET, "WSAENETRESET", ENETRESET}, + {WSAECONNABORTED, "WSAECONNABORTED", ECONNABORTED}, + {WSAECONNRESET, "WSAECONNRESET", ECONNRESET}, + {WSAENOBUFS, "WSAENOBUFS", ENOBUFS}, + {WSAEISCONN, "WSAEISCONN", EISCONN}, + {WSAENOTCONN, "WSAENOTCONN", ENOTCONN}, + {WSAESHUTDOWN, "WSAESHUTDOWN", ESHUTDOWN}, + {WSAETOOMANYREFS, "WSAETOOMANYREFS", ETOOMANYREFS}, + {WSAETIMEDOUT, "WSAETIMEDOUT", ETIMEDOUT}, + {WSAECONNREFUSED, "WSAECONNREFUSED", ECONNREFUSED}, + {WSAELOOP, "WSAELOOP", ELOOP}, + {WSAENAMETOOLONG, "WSAENAMETOOLONG", ENAMETOOLONG}, + {WSAEHOSTDOWN, "WSAEHOSTDOWN", EHOSTDOWN}, + {WSAEHOSTUNREACH, "WSAEHOSTUNREACH", EHOSTUNREACH}, + {WSAENOTEMPTY, "WSAENOTEMPTY", ENOTEMPTY}, + {WSAEPROCLIM, "WSAEPROCLIM", EPROCLIM}, + {WSAEUSERS, "WSAEUSERS", EUSERS}, + {WSAEDQUOT, "WSAEDQUOT", EDQUOT}, + {WSAESTALE, "WSAESTALE", ESTALE}, + {WSAEREMOTE, "WSAEREMOTE", EREMOTE}, + {WSAEINVAL, "WSAEINVAL", EINVAL}, + {WSAEFAULT, "WSAEFAULT", EFAULT}, + {0, "NOERROR", 0}, + {0, NULL, 0} +}; + +static int +find_winsock_errno (int why) +{ + for (int i = 0; errmap[i].s != NULL; ++i) + if (why == errmap[i].w) + return errmap[i].e; + + return EPERM; +} + +void +__set_winsock_errno (const char *fn, int ln) +{ + DWORD werr = WSAGetLastError (); + int err = find_winsock_errno (werr); + + set_errno (err); + syscall_printf ("%s:%d - winsock error %d -> errno %d", fn, ln, werr, err); +} + +/* + * Since the member `s' isn't used for debug output we can use it + * for the error text returned by herror and hstrerror. + */ +static NO_COPY struct tl host_errmap[] = { + {WSAHOST_NOT_FOUND, "Unknown host", HOST_NOT_FOUND}, + {WSATRY_AGAIN, "Host name lookup failure", TRY_AGAIN}, + {WSANO_RECOVERY, "Unknown server error", NO_RECOVERY}, + {WSANO_DATA, "No address associated with name", NO_DATA}, + {0, NULL, 0} +}; + +static void +set_host_errno () +{ + int i; + + int why = WSAGetLastError (); + + for (i = 0; host_errmap[i].w != 0; ++i) + if (why == host_errmap[i].w) + break; + + if (host_errmap[i].w != 0) + h_errno = host_errmap[i].e; + else + h_errno = NETDB_INTERNAL; +} + +inline int +DWORD_round (int n) +{ + return sizeof (DWORD) * (((n + sizeof (DWORD) - 1)) / sizeof (DWORD)); +} + +inline int +strlen_round (const char *s) +{ + if (!s) + return 0; + return DWORD_round (strlen (s) + 1); +} + +#pragma pack(push,2) +struct pservent +{ + char *s_name; + char **s_aliases; + short s_port; + char *s_proto; +}; +#pragma pack(pop) + +struct unionent +{ + char *name; + char **list; + short port_proto_addrtype; + short h_len; + union + { + char *s_proto; + char **h_addr_list; + }; +}; + +enum struct_type +{ + t_hostent, t_protoent, t_servent +}; + +static const char *entnames[] = {"host", "proto", "serv"}; + +/* Generic "dup a {host,proto,serv}ent structure" function. + This is complicated because we need to be able to free the + structure at any point and we can't rely on the pointer contents + being untouched by callers. So, we allocate a chunk of memory + large enough to hold the structure and all of the stuff it points + to then we copy the source into this new block of memory. + The 'unionent' struct is a union of all of the currently used + *ent structure. */ + +#define dup_ent(old, src, type) __dup_ent ((unionent *&) (_my_tls.locals.old), (unionent *) (src), type) +#ifdef DEBUGGING +static void * +#else +static inline void * +#endif +__dup_ent (unionent *&dst, unionent *src, struct_type type) +{ + if (dst) + debug_printf ("old %sent structure \"%s\" %p\n", entnames[type], + ((unionent *) dst)->name, dst); + + if (!src) + { + set_winsock_errno (); + return NULL; + } + + debug_printf ("duping %sent \"%s\", %p", entnames[type], src->name, src); + + /* Find the size of the raw structure minus any character strings, etc. */ + int sz, struct_sz; + switch (type) + { + case t_protoent: + struct_sz = sizeof (protoent); + break; + case t_servent: + struct_sz = sizeof (servent); + break; + case t_hostent: + struct_sz = sizeof (hostent); + break; + default: + api_fatal ("called with invalid value %d", type); + break; + } + + /* Every *ent begins with a name. Calculate it's length. */ + int namelen = strlen_round (src->name); + sz = struct_sz + namelen; + + char **av; + /* The next field in every *ent is an argv list of "something". + Calculate the number of components and how much space the + character strings will take. */ + int list_len = 0; + for (av = src->list; av && *av; av++) + { + list_len++; + sz += sizeof (char **) + strlen_round (*av); + } + + /* NULL terminate if there actually was a list */ + if (av) + { + sz += sizeof (char **); + list_len++; + } + + /* Do servent/hostent specific processing */ + int protolen = 0; + int addr_list_len = 0; + char *s_proto = NULL; + if (type == t_servent) + { + if (src->s_proto) + { + /* Windows 95 idiocy. Structure is misaligned on Windows 95. + Kludge around this by trying a different pointer alignment. */ + if (!IsBadStringPtr (src->s_proto, INT32_MAX)) + s_proto = src->s_proto; + else if (!IsBadStringPtr (((pservent *) src)->s_proto, INT32_MAX)) + s_proto = ((pservent *) src)->s_proto; + sz += (protolen = strlen_round (s_proto)); + } + } + else if (type == t_hostent) + { + /* Calculate the length and storage used for h_addr_list */ + for (av = src->h_addr_list; av && *av; av++) + { + addr_list_len++; + sz += sizeof (char **) + DWORD_round (src->h_len); + } + if (av) + { + sz += sizeof (char **); + addr_list_len++; + } + } + + /* Allocate the storage needed. Allocate a rounded size to attempt to force + reuse of this buffer so that a poorly-written caller will not be using + a freed buffer. */ + unsigned rsz = 256 * ((sz + 255) / 256); + dst = (unionent *) realloc (dst, rsz); + + /* Hopefully, this worked. */ + if (dst) + { + memset (dst, 0, sz); + /* This field is common to all *ent structures but named differently + in each, of course. */ + dst->port_proto_addrtype = src->port_proto_addrtype; + + char *dp = ((char *) dst) + struct_sz; + if (namelen) + { + /* Copy the name field to dst, using space just beyond the end of + the dst structure. */ + strcpy (dst->name = dp, src->name); + dp += namelen; + } + + /* Copy the 'list' type to dst, using space beyond end of structure + + storage for name. */ + if (src->list) + { + char **dav = dst->list = (char **) dp; + dp += sizeof (char **) * list_len; + for (av = src->list; av && *av; av++) + { + int len = strlen (*av) + 1; + memcpy (*dav++ = dp, *av, len); + dp += DWORD_round (len); + } + } + + /* Do servent/protoent/hostent specific processing. */ + if (type == t_protoent) + debug_printf ("protoent %s %x %x", dst->name, dst->list, dst->port_proto_addrtype); + else if (type == t_servent) + { + if (s_proto) + { + strcpy (dst->s_proto = dp, s_proto); + dp += protolen; + } + } + else if (type == t_hostent) + { + /* Transfer h_len and duplicate contents of h_addr_list, using + memory after 'list' allocation. */ + dst->h_len = src->h_len; + char **dav = dst->h_addr_list = (char **) dp; + dp += sizeof (char **) * addr_list_len; + for (av = src->h_addr_list; av && *av; av++) + { + memcpy (*dav++ = dp, *av, src->h_len); + dp += DWORD_round (src->h_len); + } + } + /* Sanity check that we did our bookkeeping correctly. */ + assert ((dp - (char *) dst) == sz); + } + debug_printf ("duped %sent \"%s\", %p", entnames[type], dst ? dst->name : "<null!>", dst); + return dst; +} + +/* exported as getprotobyname: standards? */ +extern "C" struct protoent * +cygwin_getprotobyname (const char *p) +{ + myfault efault; + if (efault.faulted (EFAULT)) + return NULL; + return (protoent *) dup_ent (protoent_buf, getprotobyname (p), t_protoent); +} + +/* exported as getprotobynumber: standards? */ +extern "C" struct protoent * +cygwin_getprotobynumber (int number) +{ + return (protoent *) dup_ent (protoent_buf, getprotobynumber (number), t_protoent); +} + +bool +fdsock (cygheap_fdmanip& fd, const device *dev, SOCKET soc) +{ + if (wincap.has_set_handle_information ()) + { + /* NT systems apparently set sockets to inheritable by default */ + SetHandleInformation ((HANDLE) soc, HANDLE_FLAG_INHERIT, 0); + debug_printf ("reset socket inheritance"); + } + else + debug_printf ("not setting socket inheritance"); + fd = build_fh_dev (*dev); + if (!fd.isopen ()) + return false; + fd->set_io_handle ((HANDLE) soc); + fd->set_flags (O_RDWR | O_BINARY); + fd->uninterruptible_io (true); + cygheap->fdtab.inc_need_fixup_before (); + debug_printf ("fd %d, name '%s', soc %p", (int) fd, dev->name, soc); +#if 0 + /* Same default buffer sizes as on Linux (instead of WinSock default 8K). + + NOT. If the SO_RCVBUF size exceeds 65535(*), and if the socket is + connected to a remote machine, then duplicating the socket on + fork/exec fails with WinSock error 10022, WSAEINVAL. Given that, + there's not any good reason to set the buffer sizes at all. So we + stick with the defaults. However, an explanation for this weird + behaviour would be nice. I keep this stuff in the code for later + generations. Archeological programmers might find it useful. + + (*) Maximum normal TCP window size. Coincidence? */ + + int rmem = dev == tcp_dev ? 87380 : 120832; + int wmem = dev == tcp_dev ? 16384 : 120832; + if (::setsockopt (soc, SOL_SOCKET, SO_RCVBUF, (char *) &rmem, sizeof (int))) + debug_printf ("setsockopt(SO_RCVBUF) failed, %lu", WSAGetLastError ()); + if (::setsockopt (soc, SOL_SOCKET, SO_SNDBUF, (char *) &wmem, sizeof (int))) + debug_printf ("setsockopt(SO_SNDBUF) failed, %lu", WSAGetLastError ()); +#endif + return true; +} + +/* exported as socket: standards? */ +extern "C" int +cygwin_socket (int af, int type, int protocol) +{ + int res = -1; + SOCKET soc = 0; + + debug_printf ("socket (%d, %d, %d)", af, type, protocol); + + soc = socket (af == AF_LOCAL ? AF_INET : af, type, + af == AF_LOCAL ? 0 : protocol); + + if (soc == INVALID_SOCKET) + { + set_winsock_errno (); + goto done; + } + + const device *dev; + + if (af == AF_LOCAL) + dev = type == SOCK_STREAM ? stream_dev : dgram_dev; + else + dev = type == SOCK_STREAM ? tcp_dev : udp_dev; + + { + cygheap_fdnew fd; + if (fd < 0 || !fdsock (fd, dev, soc)) + closesocket (soc); + else + { + ((fhandler_socket *) fd)->set_addr_family (af); + ((fhandler_socket *) fd)->set_socket_type (type); + res = fd; + } + } + +done: + syscall_printf ("%d = socket (%d, %d, %d)", res, af, type, protocol); + return res; +} + +/* exported as sendto: standards? */ +extern "C" int +cygwin_sendto (int fd, const void *buf, size_t len, int flags, + const struct sockaddr *to, socklen_t tolen) +{ + int res; + sig_dispatch_pending (); + + fhandler_socket *fh = get (fd); + + myfault efault; + if (efault.faulted (EFAULT) || !fh) + res = -1; + else + res = fh->sendto (buf, len, flags, to, tolen); + + syscall_printf ("%d = sendto (%d, %p, %d, %x, %p, %d)", + res, fd, buf, len, flags, to, tolen); + + return res; +} + +/* exported as recvfrom: standards? */ +extern "C" int +cygwin_recvfrom (int fd, void *buf, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen) +{ + int res; + sig_dispatch_pending (); + + fhandler_socket *fh = get (fd); + + myfault efault; + if (efault.faulted (EFAULT) || !fh) + res = -1; + else if ((res = len) != 0) + res = fh->recvfrom (buf, len, flags, from, fromlen); + + syscall_printf ("%d = recvfrom (%d, %p, %d, %x, %p, %p)", + res, fd, buf, len, flags, from, fromlen); + + return res; +} + +static int +convert_ws1_ip_optname (int optname) +{ + static int ws2_optname[] = + { + 0, + IP_OPTIONS, + IP_MULTICAST_IF, + IP_MULTICAST_TTL, + IP_MULTICAST_LOOP, + IP_ADD_MEMBERSHIP, + IP_DROP_MEMBERSHIP, + IP_TTL, + IP_TOS, + IP_DONTFRAGMENT + }; + return (optname < 1 || optname > _WS1_IP_DONTFRAGMENT) + ? optname + : ws2_optname[optname]; +} + +/* exported as setsockopt: standards? */ +extern "C" int +cygwin_setsockopt (int fd, int level, int optname, const void *optval, + socklen_t optlen) +{ + int res; + fhandler_socket *fh = get (fd); + + myfault efault; + if (efault.faulted (EFAULT) || !fh) + res = -1; + else + { + /* Old applications still use the old Winsock1 IPPROTO_IP values. */ + if (level == IPPROTO_IP && CYGWIN_VERSION_CHECK_FOR_USING_WINSOCK1_VALUES) + optname = convert_ws1_ip_optname (optname); + + res = setsockopt (fh->get_socket (), level, optname, + (const char *) optval, optlen); + + if (optlen == 4) + syscall_printf ("setsockopt optval=%x", *(long *) optval); + + if (res) + { + /* KB 248611: + + Windows 2000 and above don't support setting the IP_TOS field + with setsockopt. Additionally, TOS was always (also under 9x + and NT) only implemented for UDP and ICMP, never for TCP. + + The difference is that beginning with Windows 2000 the + setsockopt call returns WinSock error 10022, WSAEINVAL when + trying to set the IP_TOS field, instead of just ignoring the + call. This is *not* explained in KB 248611, but only in KB + 258978. + + Either case, the official workaround is to add a new registry + DWORD value HKLM/System/CurrentControlSet/Services/Tcpip/... + ... Parameters/DisableUserTOSSetting, set to 0, and reboot. + + Sidenote: The reasoning for dropping ToS in Win2K is that ToS + per RFC 1349 is incompatible with DiffServ per RFC 2474/2475. + + We just ignore the return value of setting IP_TOS under Windows + 2000 and above entirely. */ + if (level == IPPROTO_IP && optname == IP_TOS + && WSAGetLastError () == WSAEINVAL + && wincap.has_disabled_user_tos_setting ()) + { + debug_printf ("Faked IP_TOS success"); + res = 0; + } + else + set_winsock_errno (); + } + else if (level == SOL_SOCKET && optname == SO_REUSEADDR) + fh->saw_reuseaddr (*(int *) optval); + } + + syscall_printf ("%d = setsockopt (%d, %d, %x, %p, %d)", + res, fd, level, optname, optval, optlen); + return res; +} + +/* exported as getsockopt: standards? */ +extern "C" int +cygwin_getsockopt (int fd, int level, int optname, void *optval, + socklen_t *optlen) +{ + int res; + fhandler_socket *fh = get (fd); + + myfault efault; + if (efault.faulted (EFAULT) || !fh) + res = -1; + else if (optname == SO_PEERCRED) + { + struct ucred *cred = (struct ucred *) optval; + res = fh->getpeereid (&cred->pid, &cred->uid, &cred->gid); + } + else + { + /* Old applications still use the old Winsock1 IPPROTO_IP values. */ + if (level == IPPROTO_IP && CYGWIN_VERSION_CHECK_FOR_USING_WINSOCK1_VALUES) + optname = convert_ws1_ip_optname (optname); + res = getsockopt (fh->get_socket (), level, optname, (char *) optval, + (int *) optlen); + + if (optname == SO_ERROR) + { + int *e = (int *) optval; + + debug_printf ("WinSock SO_ERROR = %d", *e); + *e = find_winsock_errno (*e); + } + + if (res) + set_winsock_errno (); + } + + syscall_printf ("%d = getsockopt (%d, %d, 0x%x, %p, %p)", + res, fd, level, optname, optval, optlen); + return res; +} + +extern "C" int +getpeereid (int fd, __uid32_t *euid, __gid32_t *egid) +{ + sig_dispatch_pending (); + fhandler_socket *fh = get (fd); + if (fh) + return fh->getpeereid (NULL, euid, egid); + return -1; +} + +/* exported as connect: standards? */ +extern "C" int +cygwin_connect (int fd, const struct sockaddr *name, socklen_t namelen) +{ + int res; + sig_dispatch_pending (); + + fhandler_socket *fh = get (fd); + + myfault efault; + if (efault.faulted (EFAULT) || !fh) + res = -1; + else + { + bool was_blocking = false; + if (!fh->is_nonblocking ()) + { + int nonblocking = 1; + fh->ioctl (FIONBIO, &nonblocking); + was_blocking = true; + } + res = fh->connect (name, namelen); + if (was_blocking) + { + if (res == -1 && get_errno () == EINPROGRESS) + { + size_t fds_size = howmany (fd + 1, NFDBITS) * sizeof (fd_mask); + fd_set *write_fds = (fd_set *) alloca (fds_size); + fd_set *except_fds = (fd_set *) alloca (fds_size); + memset (write_fds, 0, fds_size); + memset (except_fds, 0, fds_size); + FD_SET (fd, write_fds); + FD_SET (fd, except_fds); + res = cygwin_select (fd + 1, NULL, write_fds, except_fds, NULL); + if (res > 0 && FD_ISSET (fd, except_fds)) + { + res = -1; + for (;;) + { + int err; + int len = sizeof err; + cygwin_getsockopt (fd, SOL_SOCKET, SO_ERROR, + (void *) &err, &len); + if (err) + { + set_errno (err); + break; + } + low_priority_sleep (0); + } + } + else if (res > 0) + res = 0; + else + { + WSASetLastError (WSAEINPROGRESS); + set_winsock_errno (); + } + } + int nonblocking = 0; + fh->ioctl (FIONBIO, &nonblocking); + } + } + + syscall_printf ("%d = connect (%d, %p, %d)", res, fd, name, namelen); + + return res; +} + +/* exported as getservbyname: standards? */ +extern "C" struct servent * +cygwin_getservbyname (const char *name, const char *proto) +{ + sig_dispatch_pending (); + myfault efault; + if (efault.faulted (EFAULT)) + return NULL; + + servent *res = (servent *) dup_ent (servent_buf, getservbyname (name, proto), t_servent); + syscall_printf ("%p = getservbyname (%s, %s)", res, name, proto); + return res; +} + +/* exported as getservbyport: standards? */ +extern "C" struct servent * +cygwin_getservbyport (int port, const char *proto) +{ + sig_dispatch_pending (); + myfault efault; + if (efault.faulted (EFAULT)) + return NULL; + + servent *res = (servent *) dup_ent (servent_buf, getservbyport (port, proto), t_servent); + syscall_printf ("%p = getservbyport (%d, %s)", _my_tls.locals.servent_buf, port, proto); + return res; +} + +extern "C" int +cygwin_gethostname (char *name, size_t len) +{ + sig_dispatch_pending (); + myfault efault; + if (efault.faulted (EFAULT)) + return -1; + + if (gethostname (name, len)) + { + DWORD local_len = len; + + if (!GetComputerNameA (name, &local_len)) + { + set_winsock_errno (); + return -1; + } + } + debug_printf ("name %s", name); + return 0; +} + +/* exported as gethostbyname: standards? */ +extern "C" struct hostent * +cygwin_gethostbyname (const char *name) +{ + sig_dispatch_pending (); + myfault efault; + if (efault.faulted (EFAULT)) + return NULL; + + unsigned char tmp_addr[4]; + struct hostent tmp, *h; + char *tmp_aliases[1] = {0}; + char *tmp_addr_list[2] = {0,0}; + unsigned int a, b, c, d; + char dummy; + + if (sscanf (name, "%u.%u.%u.%u%c", &a, &b, &c, &d, &dummy) != 4 + || a >= 256 || b >= 256 || c >= 256 || d >= 256) + h = gethostbyname (name); + else + { + /* In case you don't have DNS, at least x.x.x.x still works */ + memset (&tmp, 0, sizeof (tmp)); + tmp_addr[0] = a; + tmp_addr[1] = b; + tmp_addr[2] = c; + tmp_addr[3] = d; + tmp_addr_list[0] = (char *) tmp_addr; + tmp.h_name = name; + tmp.h_aliases = tmp_aliases; + tmp.h_addrtype = 2; + tmp.h_length = 4; + tmp.h_addr_list = tmp_addr_list; + h = &tmp; + } + + hostent *res = (hostent *) dup_ent (hostent_buf, h, t_hostent); + if (res) + debug_printf ("h_name %s", res->h_name); + else + { + debug_printf ("dup_ent returned NULL for name %s, h %p", name, h); + set_host_errno (); + } + return res; +} + +/* exported as gethostbyaddr: standards? */ +extern "C" struct hostent * +cygwin_gethostbyaddr (const char *addr, int len, int type) +{ + sig_dispatch_pending (); + myfault efault; + if (efault.faulted (EFAULT)) + return NULL; + + hostent *res = (hostent *) dup_ent (hostent_buf, gethostbyaddr (addr, len, type), t_hostent); + if (res) + debug_printf ("h_name %s", _my_tls.locals.hostent_buf->h_name); + else + set_host_errno (); + return res; +} + +/* exported as accept: standards? */ +extern "C" int +cygwin_accept (int fd, struct sockaddr *peer, socklen_t *len) +{ + int res; + sig_dispatch_pending (); + + fhandler_socket *fh = get (fd); + + myfault efault; + if (efault.faulted (EFAULT) || !fh) + res = -1; + else + { + if (!fh->is_nonblocking ()) + { + size_t fds_size = howmany (fd + 1, NFDBITS) * sizeof (fd_mask); + fd_set *read_fds = (fd_set *) alloca (fds_size); + memset (read_fds, 0, fds_size); + FD_SET (fd, read_fds); + res = cygwin_select (fd + 1, read_fds, NULL, NULL, NULL); + if (res == -1) + return -1; + } + res = fh->accept (peer, len); + } + + syscall_printf ("%d = accept (%d, %p, %p)", res, fd, peer, len); + return res; +} + +/* exported as bind: standards? */ +extern "C" int +cygwin_bind (int fd, const struct sockaddr *my_addr, socklen_t addrlen) +{ + int res; + sig_dispatch_pending (); + fhandler_socket *fh = get (fd); + + myfault efault; + if (efault.faulted (EFAULT) || !fh) + res = -1; + else + res = fh->bind (my_addr, addrlen); + + syscall_printf ("%d = bind (%d, %p, %d)", res, fd, my_addr, addrlen); + return res; +} + +/* exported as getsockname: standards? */ +extern "C" int +cygwin_getsockname (int fd, struct sockaddr *addr, socklen_t *namelen) +{ + int res; + sig_dispatch_pending (); + + fhandler_socket *fh = get (fd); + + myfault efault; + if (efault.faulted (EFAULT) || !fh) + res = -1; + else + res = fh->getsockname (addr, namelen); + + syscall_printf ("%d = getsockname (%d, %p, %p)", res, fd, addr, namelen); + return res; +} + +/* exported as listen: standards? */ +extern "C" int +cygwin_listen (int fd, int backlog) +{ + int res; + sig_dispatch_pending (); + fhandler_socket *fh = get (fd); + + if (!fh) + res = -1; + else + res = fh->listen (backlog); + + syscall_printf ("%d = listen (%d, %d)", res, fd, backlog); + return res; +} + +/* exported as shutdown: standards? */ +extern "C" int +cygwin_shutdown (int fd, int how) +{ + int res; + sig_dispatch_pending (); + + fhandler_socket *fh = get (fd); + + if (!fh) + res = -1; + else + res = fh->shutdown (how); + + syscall_printf ("%d = shutdown (%d, %d)", res, fd, how); + return res; +} + +/* exported as hstrerror: BSD 4.3 */ +extern "C" const char * +cygwin_hstrerror (int err) +{ + int i; + + for (i = 0; host_errmap[i].e != 0; ++i) + if (err == host_errmap[i].e) + break; + + return host_errmap[i].s; +} + +/* exported as herror: BSD 4.3 */ +extern "C" void +cygwin_herror (const char *s) +{ + myfault efault; + if (efault.faulted ()) + return; + if (cygheap->fdtab.not_open (2)) + return; + + if (s) + { + write (2, s, strlen (s)); + write (2, ": ", 2); + } + + const char *h_errstr = cygwin_hstrerror (h_errno); + + if (!h_errstr) + switch (h_errno) + { + case NETDB_INTERNAL: + h_errstr = "Resolver internal error"; + break; + case NETDB_SUCCESS: + h_errstr = "Resolver error 0 (no error)"; + break; + default: + h_errstr = "Unknown resolver error"; + break; + } + write (2, h_errstr, strlen (h_errstr)); + write (2, "\n", 1); +} + +/* exported as getpeername: standards? */ +extern "C" int +cygwin_getpeername (int fd, struct sockaddr *name, socklen_t *len) +{ + int res; + sig_dispatch_pending (); + + fhandler_socket *fh = get (fd); + + myfault efault; + if (efault.faulted (EFAULT) || !fh) + res = -1; + else + res = fh->getpeername (name, len); + + syscall_printf ("%d = getpeername (%d) %d", res, fd, (fh ? fh->get_socket () : -1)); + return res; +} + +/* exported as recv: standards? */ +extern "C" int +cygwin_recv (int fd, void *buf, size_t len, int flags) +{ + return cygwin_recvfrom (fd, buf, len, flags, NULL, NULL); +} + +/* exported as send: standards? */ +extern "C" int +cygwin_send (int fd, const void *buf, size_t len, int flags) +{ + return cygwin_sendto (fd, buf, len, flags, NULL, 0); +} + +/* getdomainname: standards? */ +extern "C" int +getdomainname (char *domain, size_t len) +{ + /* + * This works for Win95 only if the machine is configured to use MS-TCP. + * If a third-party TCP is being used this will fail. + * FIXME: On Win95, is there a way to portably check the TCP stack + * in use and include paths for the Domain name in each ? + * Punt for now and assume MS-TCP on Win95. + */ + sig_dispatch_pending (); + myfault efault; + if (efault.faulted (EFAULT)) + return -1; + + PFIXED_INFO info = NULL; + ULONG size = 0; + + if (GetNetworkParams(info, &size) == ERROR_BUFFER_OVERFLOW + && (info = (PFIXED_INFO) alloca(size)) + && GetNetworkParams(info, &size) == ERROR_SUCCESS) + { + strncpy(domain, info->DomainName, len); + return 0; + } + + /* This is only used by Win95 and NT <= 4.0. + The registry names are language independent. + FIXME: Handle DHCP on Win95. The DhcpDomain(s) may be available + in ..VxD\DHCP\DhcpInfoXX\OptionInfo, RFC 1533 format */ + + reg_key r (HKEY_LOCAL_MACHINE, KEY_READ, + (!wincap.is_winnt ()) ? "System" : "SYSTEM", + "CurrentControlSet", "Services", + (!wincap.is_winnt ()) ? "VxD" : "Tcpip", + (!wincap.is_winnt ()) ? "MSTCP" : "Parameters", NULL); + + if (!r.error ()) + { + int res1, res2 = 0; /* Suppress compiler warning */ + res1 = r.get_string ("Domain", domain, len, ""); + if (res1 != ERROR_SUCCESS || !domain[0]) + res2 = r.get_string ("DhcpDomain", domain, len, ""); + if (res1 == ERROR_SUCCESS || res2 == ERROR_SUCCESS) + return 0; + } + __seterrno (); + return -1; +} + +/* Fill out an ifconf struct. */ + +/* + * IFCONF 98/ME, NTSP4, W2K: + * Use IP Helper Library + */ +static void +get_2k_ifconf (struct ifconf *ifc, int what) +{ + int cnt = 0; + int ethId = 0, pppId = 0, slpId = 0, tokId = 0; + + /* Union maps buffer to correct struct */ + struct ifreq *ifr = ifc->ifc_req; + + DWORD ip_cnt, lip, lnp; + DWORD siz_ip_table = 0; + PMIB_IPADDRTABLE ipt; + PMIB_IFROW ifrow; + struct sockaddr_in *sa = NULL; + struct sockaddr *so = NULL; + + typedef struct ifcount_t + { + DWORD ifIndex; + size_t count; + unsigned int enumerated; // for eth0:1 + unsigned int classId; // for eth0, tok0 ... + + }; + ifcount_t *iflist, *ifEntry; + + if (GetIpAddrTable (NULL, &siz_ip_table, TRUE) == ERROR_INSUFFICIENT_BUFFER + && (ifrow = (PMIB_IFROW) alloca (sizeof (MIB_IFROW))) + && (ipt = (PMIB_IPADDRTABLE) alloca (siz_ip_table)) + && !GetIpAddrTable (ipt, &siz_ip_table, TRUE)) + { + iflist = + (ifcount_t *) alloca (sizeof (ifcount_t) * (ipt->dwNumEntries + 1)); + memset (iflist, 0, sizeof (ifcount_t) * (ipt->dwNumEntries + 1)); + for (ip_cnt = 0; ip_cnt < ipt->dwNumEntries; ++ip_cnt) + { + ifEntry = iflist; + /* search for matching entry (and stop at first free entry) */ + while (ifEntry->count != 0) + { + if (ifEntry->ifIndex == ipt->table[ip_cnt].dwIndex) + break; + ifEntry++; + } + if (ifEntry->count == 0) + { + ifEntry->count = 1; + ifEntry->ifIndex = ipt->table[ip_cnt].dwIndex; + } + else + { + ifEntry->count++; + } + } + // reset the last element. This is just the stopper for the loop. + iflist[ipt->dwNumEntries].count = 0; + + /* Iterate over all configured IP-addresses */ + for (ip_cnt = 0; ip_cnt < ipt->dwNumEntries; ++ip_cnt) + { + memset (ifrow, 0, sizeof (MIB_IFROW)); + ifrow->dwIndex = ipt->table[ip_cnt].dwIndex; + if (GetIfEntry (ifrow) != NO_ERROR) + continue; + + ifcount_t *ifEntry = iflist; + + /* search for matching entry (and stop at first free entry) */ + while (ifEntry->count != 0) + { + if (ifEntry->ifIndex == ipt->table[ip_cnt].dwIndex) + break; + ifEntry++; + } + + /* Setup the interface name */ + switch (ifrow->dwType) + { + case MIB_IF_TYPE_TOKENRING: + if (ifEntry->enumerated == 0) + { + ifEntry->classId = tokId++; + __small_sprintf (ifr->ifr_name, "tok%u", + ifEntry->classId); + } + else + { + __small_sprintf (ifr->ifr_name, "tok%u:%u", + ifEntry->classId, + ifEntry->enumerated - 1); + } + ifEntry->enumerated++; + break; + case MIB_IF_TYPE_ETHERNET: + if (ifEntry->enumerated == 0) + { + ifEntry->classId = ethId++; + __small_sprintf (ifr->ifr_name, "eth%u", + ifEntry->classId); + } + else + { + __small_sprintf (ifr->ifr_name, "eth%u:%u", + ifEntry->classId, + ifEntry->enumerated - 1); + } + ifEntry->enumerated++; + break; + case MIB_IF_TYPE_PPP: + if (ifEntry->enumerated == 0) + { + ifEntry->classId = pppId++; + __small_sprintf (ifr->ifr_name, "ppp%u", + ifEntry->classId); + } + else + { + __small_sprintf (ifr->ifr_name, "ppp%u:%u", + ifEntry->classId, + ifEntry->enumerated - 1); + } + ifEntry->enumerated++; + break; + case MIB_IF_TYPE_SLIP: + if (ifEntry->enumerated == 0) + { + ifEntry->classId = slpId++; + __small_sprintf (ifr->ifr_name, "slp%u", + ifEntry->classId); + } + else + { + __small_sprintf (ifr->ifr_name, "slp%u:%u", + ifEntry->classId, + ifEntry->enumerated - 1); + } + ifEntry->enumerated++; + break; + case MIB_IF_TYPE_LOOPBACK: + strcpy (ifr->ifr_name, "lo"); + break; + default: + continue; + } + /* setup sockaddr struct */ + switch (what) + { + case SIOCGIFCONF: + case SIOCGIFADDR: + sa = (struct sockaddr_in *) &ifr->ifr_addr; + sa->sin_addr.s_addr = ipt->table[ip_cnt].dwAddr; + sa->sin_family = AF_INET; + sa->sin_port = 0; + break; + case SIOCGIFBRDADDR: + sa = (struct sockaddr_in *) &ifr->ifr_broadaddr; +#if 0 + /* Unfortunately, the field returns only crap. */ + sa->sin_addr.s_addr = ipt->table[ip_cnt].dwBCastAddr; +#else + lip = ipt->table[ip_cnt].dwAddr; + lnp = ipt->table[ip_cnt].dwMask; + sa->sin_addr.s_addr = lip & lnp | ~lnp; + sa->sin_family = AF_INET; + sa->sin_port = 0; +#endif + break; + case SIOCGIFNETMASK: + sa = (struct sockaddr_in *) &ifr->ifr_netmask; + sa->sin_addr.s_addr = ipt->table[ip_cnt].dwMask; + sa->sin_family = AF_INET; + sa->sin_port = 0; + break; + case SIOCGIFHWADDR: + so = &ifr->ifr_hwaddr; + for (UINT i = 0; i < IFHWADDRLEN; ++i) + if (i >= ifrow->dwPhysAddrLen) + so->sa_data[i] = '\0'; + else + so->sa_data[i] = ifrow->bPhysAddr[i]; + so->sa_family = AF_INET; + break; + case SIOCGIFMETRIC: + ifr->ifr_metric = 1; + break; + case SIOCGIFMTU: + ifr->ifr_mtu = ifrow->dwMtu; + break; + } + ++cnt; + if ((caddr_t)++ ifr > + ifc->ifc_buf + ifc->ifc_len - sizeof (struct ifreq)) + goto done; + } + } + +done: + /* Set the correct length */ + ifc->ifc_len = cnt * sizeof (struct ifreq); +} + +/* + * IFCONF Windows NT < SP4: + * Look at the Bind value in + * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Linkage\ + * This is a REG_MULTI_SZ with strings of the form: + * \Device\<Netcard>, where netcard is the name of the net device. + * Then look under: + * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<NetCard>\ + * Parameters\Tcpip + * at the IPAddress, Subnetmask and DefaultGateway values for the + * required values. + */ +static void +get_nt_ifconf (struct ifconf *ifc, int what) +{ + HKEY key; + unsigned long lip, lnp; + struct sockaddr_in *sa = NULL; + struct sockaddr *so = NULL; + DWORD size; + int cnt = 1; + char *binding = (char *) 0; + + /* Union maps buffer to correct struct */ + struct ifreq *ifr = ifc->ifc_req; + + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, + "SYSTEM\\" + "CurrentControlSet\\" + "Services\\" + "Tcpip\\" "Linkage", + 0, KEY_READ, &key) == ERROR_SUCCESS) + { + if (RegQueryValueEx (key, "Bind", + NULL, NULL, + NULL, &size) == ERROR_SUCCESS) + { + binding = (char *) alloca (size); + if (RegQueryValueEx (key, "Bind", + NULL, NULL, + (unsigned char *) binding, + &size) != ERROR_SUCCESS) + { + binding = NULL; + } + } + RegCloseKey (key); + } + + if (binding) + { + char *bp, eth[2] = "/"; + char cardkey[256], ipaddress[256], netmask[256]; + + for (bp = binding; *bp; bp += strlen (bp) + 1) + { + bp += strlen ("\\Device\\"); + strcpy (cardkey, "SYSTEM\\CurrentControlSet\\Services\\"); + strcat (cardkey, bp); + strcat (cardkey, "\\Parameters\\Tcpip"); + + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, cardkey, + 0, KEY_READ, &key) != ERROR_SUCCESS) + continue; + + if (RegQueryValueEx (key, "IPAddress", + NULL, NULL, + (unsigned char *) ipaddress, + (size = 256, &size)) == ERROR_SUCCESS + && RegQueryValueEx (key, "SubnetMask", + NULL, NULL, + (unsigned char *) netmask, + (size = 256, &size)) == ERROR_SUCCESS) + { + char *ip, *np; + char dhcpaddress[256], dhcpnetmask[256]; + + for (ip = ipaddress, np = netmask; + *ip && *np; + ip += strlen (ip) + 1, np += strlen (np) + 1) + { + if ((caddr_t)++ ifr > ifc->ifc_buf + + ifc->ifc_len - sizeof (struct ifreq)) + break; + + if (!strncmp (bp, "NdisWan", 7)) + { + strcpy (ifr->ifr_name, "ppp"); + strcat (ifr->ifr_name, bp + 7); + } + else + { + ++*eth; + strcpy (ifr->ifr_name, "eth"); + strcat (ifr->ifr_name, eth); + } + memset (&ifr->ifr_addr, '\0', sizeof ifr->ifr_addr); + if (cygwin_inet_addr (ip) == 0L + && RegQueryValueEx (key, "DhcpIPAddress", + NULL, NULL, + (unsigned char *) dhcpaddress, + (size = 256, &size)) + == ERROR_SUCCESS + && RegQueryValueEx (key, "DhcpSubnetMask", + NULL, NULL, + (unsigned char *) dhcpnetmask, + (size = 256, &size)) + == ERROR_SUCCESS) + { + switch (what) + { + case SIOCGIFCONF: + case SIOCGIFADDR: + sa = (struct sockaddr_in *) &ifr->ifr_addr; + sa->sin_addr.s_addr = + cygwin_inet_addr (dhcpaddress); + sa->sin_family = AF_INET; + sa->sin_port = 0; + break; + case SIOCGIFBRDADDR: + lip = cygwin_inet_addr (dhcpaddress); + lnp = cygwin_inet_addr (dhcpnetmask); + sa = (struct sockaddr_in *) &ifr->ifr_broadaddr; + sa->sin_addr.s_addr = lip & lnp | ~lnp; + sa->sin_family = AF_INET; + sa->sin_port = 0; + break; + case SIOCGIFNETMASK: + sa = (struct sockaddr_in *) &ifr->ifr_netmask; + sa->sin_addr.s_addr = + cygwin_inet_addr (dhcpnetmask); + sa->sin_family = AF_INET; + sa->sin_port = 0; + break; + case SIOCGIFHWADDR: + so = &ifr->ifr_hwaddr; + memset (so->sa_data, 0, IFHWADDRLEN); + so->sa_family = AF_INET; + break; + case SIOCGIFMETRIC: + ifr->ifr_metric = 1; + break; + case SIOCGIFMTU: + ifr->ifr_mtu = 1500; + break; + } + } + else + { + switch (what) + { + case SIOCGIFCONF: + case SIOCGIFADDR: + sa = (struct sockaddr_in *) &ifr->ifr_addr; + sa->sin_addr.s_addr = cygwin_inet_addr (ip); + sa->sin_family = AF_INET; + sa->sin_port = 0; + break; + case SIOCGIFBRDADDR: + lip = cygwin_inet_addr (ip); + lnp = cygwin_inet_addr (np); + sa = (struct sockaddr_in *) &ifr->ifr_broadaddr; + sa->sin_addr.s_addr = lip & lnp | ~lnp; + sa->sin_family = AF_INET; + sa->sin_port = 0; + break; + case SIOCGIFNETMASK: + sa = (struct sockaddr_in *) &ifr->ifr_netmask; + sa->sin_addr.s_addr = cygwin_inet_addr (np); + sa->sin_family = AF_INET; + sa->sin_port = 0; + break; + case SIOCGIFHWADDR: + so = &ifr->ifr_hwaddr; + memset (so->sa_data, 0, IFHWADDRLEN); + so->sa_family = AF_INET; + break; + case SIOCGIFMETRIC: + ifr->ifr_metric = 1; + break; + case SIOCGIFMTU: + ifr->ifr_mtu = 1500; + break; + } + } + ++cnt; + } + } + RegCloseKey (key); + } + } + + /* Set the correct length */ + ifc->ifc_len = cnt * sizeof (struct ifreq); +} + +/* + * IFCONF Windows 95: + * HKLM/Enum/Network/MSTCP/"*" + * -> Value "Driver" enthält Subkey relativ zu + * HKLM/System/CurrentControlSet/Class/ + * -> In Subkey "Bindings" die Values aufzählen + * -> Enthält Subkeys der Form "VREDIR\*" + * Das * ist ein Subkey relativ zu + * HKLM/System/CurrentControlSet/Class/Net/ + * HKLM/System/CurrentControlSet/Class/"Driver" + * -> Value "IPAddress" + * -> Value "IPMask" + * HKLM/System/CurrentControlSet/Class/Net/"*"(aus "VREDIR\*") + * -> Wenn Value "AdapterName" == "MS$PPP" -> ppp interface + * -> Value "DriverDesc" enthält den Namen + * + */ +static void +get_95_ifconf (struct ifconf *ifc, int what) +{ + HKEY key; + unsigned long lip, lnp; + struct sockaddr_in *sa = NULL; + struct sockaddr *so = NULL; + FILETIME update; + LONG res; + DWORD size; + int cnt = 1; + char ifname[256]; + char eth[2] = "/"; + char ppp[2] = "/"; + + /* Union maps buffer to correct struct */ + struct ifreq *ifr = ifc->ifc_req; + + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Enum\\Network\\MSTCP", + 0, KEY_READ, &key) != ERROR_SUCCESS) + { + /* Set the correct length */ + ifc->ifc_len = cnt * sizeof (struct ifreq); + return; + } + + for (int i = 0; + (res = RegEnumKeyEx (key, i, ifname, + (size = sizeof ifname, &size), + 0, 0, 0, &update)) != ERROR_NO_MORE_ITEMS; + ++i) + { + HKEY ifkey, subkey; + char driver[256], classname[256], netname[256]; + char adapter[256], ip[256], np[256]; + + if (res != ERROR_SUCCESS + || RegOpenKeyEx (key, ifname, 0, KEY_READ, &ifkey) != ERROR_SUCCESS) + continue; + + if (RegQueryValueEx (ifkey, "Driver", 0, + NULL, (unsigned char *) driver, + (size = sizeof driver, &size)) != ERROR_SUCCESS) + { + RegCloseKey (ifkey); + continue; + } + + strcpy (classname, "System\\CurrentControlSet\\Services\\Class\\"); + strcat (classname, driver); + if ((res = RegOpenKeyEx (HKEY_LOCAL_MACHINE, classname, + 0, KEY_READ, &subkey)) != ERROR_SUCCESS) + { + RegCloseKey (ifkey); + continue; + } + + if (RegQueryValueEx (subkey, "IPAddress", 0, + NULL, (unsigned char *) ip, + (size = sizeof ip, &size)) == ERROR_SUCCESS + && RegQueryValueEx (subkey, "IPMask", 0, + NULL, (unsigned char *) np, + (size = sizeof np, &size)) == ERROR_SUCCESS) + { + if ((caddr_t)++ ifr > ifc->ifc_buf + + ifc->ifc_len - sizeof (struct ifreq)) + goto out; + + switch (what) + { + case SIOCGIFCONF: + case SIOCGIFADDR: + sa = (struct sockaddr_in *) &ifr->ifr_addr; + sa->sin_addr.s_addr = cygwin_inet_addr (ip); + sa->sin_family = AF_INET; + sa->sin_port = 0; + break; + case SIOCGIFBRDADDR: + lip = cygwin_inet_addr (ip); + lnp = cygwin_inet_addr (np); + sa = (struct sockaddr_in *) &ifr->ifr_broadaddr; + sa->sin_addr.s_addr = lip & lnp | ~lnp; + sa->sin_family = AF_INET; + sa->sin_port = 0; + break; + case SIOCGIFNETMASK: + sa = (struct sockaddr_in *) &ifr->ifr_netmask; + sa->sin_addr.s_addr = cygwin_inet_addr (np); + sa->sin_family = AF_INET; + sa->sin_port = 0; + break; + case SIOCGIFHWADDR: + so = &ifr->ifr_hwaddr; + memset (so->sa_data, 0, IFHWADDRLEN); + so->sa_family = AF_INET; + break; + case SIOCGIFMETRIC: + ifr->ifr_metric = 1; + break; + case SIOCGIFMTU: + ifr->ifr_mtu = 1500; + break; + } + } + + RegCloseKey (subkey); + + strcpy (netname, "System\\CurrentControlSet\\Services\\Class\\Net\\"); + strcat (netname, ifname); + + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, netname, + 0, KEY_READ, &subkey) != ERROR_SUCCESS) + { + RegCloseKey (ifkey); + --ifr; + continue; + } + + if (RegQueryValueEx (subkey, "AdapterName", 0, + NULL, (unsigned char *) adapter, + (size = sizeof adapter, &size)) == ERROR_SUCCESS + && strcasematch (adapter, "MS$PPP")) + { + ++*ppp; + strcpy (ifr->ifr_name, "ppp"); + strcat (ifr->ifr_name, ppp); + } + else + { + ++*eth; + strcpy (ifr->ifr_name, "eth"); + strcat (ifr->ifr_name, eth); + } + + RegCloseKey (subkey); + RegCloseKey (ifkey); + + ++cnt; + } + +out: + + RegCloseKey (key); + + /* Set the correct length */ + ifc->ifc_len = cnt * sizeof (struct ifreq); +} + +int +get_ifconf (struct ifconf *ifc, int what) +{ + unsigned long lip, lnp; + struct sockaddr_in *sa; + + sig_dispatch_pending (); + myfault efault; + if (efault.faulted (EFAULT)) + return -1; + + /* Union maps buffer to correct struct */ + struct ifreq *ifr = ifc->ifc_req; + + /* Ensure we have space for two struct ifreqs, fail if not. */ + if (ifc->ifc_len < (int) (2 * sizeof (struct ifreq))) + { + set_errno (EFAULT); + return -1; + } + + /* Set up interface lo0 first */ + strcpy (ifr->ifr_name, "lo"); + memset (&ifr->ifr_addr, '\0', sizeof (ifr->ifr_addr)); + switch (what) + { + case SIOCGIFCONF: + case SIOCGIFADDR: + sa = (struct sockaddr_in *) &ifr->ifr_addr; + sa->sin_addr.s_addr = htonl (INADDR_LOOPBACK); + sa->sin_family = AF_INET; + sa->sin_port = 0; + break; + case SIOCGIFBRDADDR: + lip = htonl (INADDR_LOOPBACK); + lnp = cygwin_inet_addr ("255.0.0.0"); + sa = (struct sockaddr_in *) &ifr->ifr_broadaddr; + sa->sin_addr.s_addr = lip & lnp | ~lnp; + sa->sin_family = AF_INET; + sa->sin_port = 0; + break; + case SIOCGIFNETMASK: + sa = (struct sockaddr_in *) &ifr->ifr_netmask; + sa->sin_addr.s_addr = cygwin_inet_addr ("255.0.0.0"); + sa->sin_family = AF_INET; + sa->sin_port = 0; + break; + case SIOCGIFHWADDR: + ifr->ifr_hwaddr.sa_family = AF_INET; + memset (ifr->ifr_hwaddr.sa_data, 0, IFHWADDRLEN); + break; + case SIOCGIFMETRIC: + ifr->ifr_metric = 1; + break; + case SIOCGIFMTU: + /* This funny value is returned by `ifconfig lo' on Linux 2.2 kernel. */ + ifr->ifr_mtu = 3924; + break; + default: + set_errno (EINVAL); + return -1; + } + + if (wincap.has_ip_helper_lib ()) + get_2k_ifconf (ifc, what); + else if (wincap.is_winnt ()) + get_nt_ifconf (ifc, what); + else + get_95_ifconf (ifc, what); + return 0; +} + +/* exported as rcmd: standards? */ +extern "C" int +cygwin_rcmd (char **ahost, unsigned short inport, char *locuser, + char *remuser, char *cmd, int *fd2p) +{ + int res = -1; + SOCKET fd2s; + + sig_dispatch_pending (); + + myfault efault; + if (efault.faulted (EFAULT)) + return (int) INVALID_SOCKET; + if (!*locuser) + { + set_errno (EINVAL); + return (int) INVALID_SOCKET; + } + + res = rcmd (ahost, inport, locuser, remuser, cmd, fd2p ? &fd2s : NULL); + if (res != (int) INVALID_SOCKET) + { + cygheap_fdnew res_fd; + + if (res_fd >= 0 && fdsock (res_fd, tcp_dev, res)) + { + ((fhandler_socket *) res_fd)->connect_state (connected); + res = res_fd; + } + else + { + closesocket (res); + res = -1; + } + + if (res >= 0 && fd2p) + { + cygheap_fdnew newfd (res_fd, false); + cygheap_fdget fd (*fd2p); + + if (newfd >= 0 && fdsock (newfd, tcp_dev, fd2s)) + { + *fd2p = newfd; + ((fhandler_socket *) fd2p)->connect_state (connected); + } + else + { + closesocket (res); + closesocket (fd2s); + res = -1; + } + } + } + + syscall_printf ("%d = rcmd (...)", res); + return res; +} + +/* The below implementation of rresvport looks pretty ugly, but there's + a problem in Winsock. The bind(2) call does not fail if a local + address is still in TIME_WAIT state, and there's no way to get this + behaviour. Unfortunately the first time when this is detected is when + the calling application tries to connect. + + One (also not really foolproof) way around this problem would be to use + the iphlpapi function GetTcpTable and to check if the port in question is + in TIME_WAIT state and if so, choose another port number. But this method + is as prone to races as the below one, or any other method using random + port numbers, etc. The below method at least tries to avoid races between + multiple applications using rrecvport. + + As for the question "why don't you just use the Winsock rresvport?"... + For some reason I do NOT understand, the call to WinSocks rresvport + corrupts the stack when Cygwin is built using -fomit-frame-pointers. + And then again, the Winsock rresvport function has the exact same + problem with reusing ports in the TIME_WAIT state as the socket/bind + method has. So there's no gain in using that function. */ + +#define PORT_LOW (IPPORT_EFSSERVER + 1) +#define PORT_HIGH (IPPORT_RESERVED - 1) +#define NUM_PORTS (PORT_HIGH - PORT_LOW + 1) + +LONG last_used_rrecvport __attribute__((section (".cygwin_dll_common"), shared)) = IPPORT_RESERVED; + +/* exported as rresvport: standards? */ +extern "C" int +cygwin_rresvport (int *port) +{ + int res; + sig_dispatch_pending (); + + myfault efault; + if (efault.faulted (EFAULT)) + return -1; + + res = socket (AF_INET, SOCK_STREAM, 0); + if (res != (int) INVALID_SOCKET) + { + LONG myport; + int ret = SOCKET_ERROR; + struct sockaddr_in sin; + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + + for (int i = 0; i < NUM_PORTS; i++) + { + while ((myport = InterlockedExchange (&last_used_rrecvport, 0)) == 0) + low_priority_sleep (0); + if (--myport < PORT_LOW) + myport = PORT_HIGH; + InterlockedExchange (&last_used_rrecvport, myport); + + sin.sin_port = htons (myport); + if (!(ret = bind (res, (struct sockaddr *) &sin, sizeof sin))) + break; + int err = WSAGetLastError (); + if (err != WSAEADDRINUSE && err != WSAEINVAL) + break; + } + if (ret == SOCKET_ERROR) + { + closesocket (res); + res = (int) INVALID_SOCKET; + } + else if (port) + *port = myport; + } + + if (res != (int) INVALID_SOCKET) + { + cygheap_fdnew res_fd; + + if (res_fd >= 0 && fdsock (res_fd, tcp_dev, res)) + res = res_fd; + else + res = -1; + } + + syscall_printf ("%d = rresvport (%d)", res, port ? *port : 0); + return res; +} + +/* socketpair: standards? */ +/* Win32 supports AF_INET only, so ignore domain and protocol arguments */ +extern "C" int +socketpair (int family, int type, int protocol, int *sb) +{ + int res = -1; + SOCKET insock, outsock, newsock; + struct sockaddr_in sock_in, sock_out; + int len; + + sig_dispatch_pending (); + myfault efault; + if (efault.faulted (EFAULT)) + return -1; + + if (family != AF_LOCAL && family != AF_INET) + { + set_errno (EAFNOSUPPORT); + goto done; + } + if (type != SOCK_STREAM && type != SOCK_DGRAM) + { + set_errno (EPROTOTYPE); + goto done; + } + if ((family == AF_LOCAL && protocol != PF_UNSPEC && protocol != PF_LOCAL) + || (family == AF_INET && protocol != PF_UNSPEC && protocol != PF_INET)) + { + set_errno (EPROTONOSUPPORT); + goto done; + } + + /* create the first socket */ + newsock = socket (AF_INET, type, 0); + if (newsock == INVALID_SOCKET) + { + debug_printf ("first socket call failed"); + set_winsock_errno (); + goto done; + } + + /* bind the socket to any unused port */ + sock_in.sin_family = AF_INET; + sock_in.sin_port = 0; + sock_in.sin_addr.s_addr = INADDR_ANY; + if (bind (newsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0) + { + debug_printf ("bind failed"); + set_winsock_errno (); + closesocket (newsock); + goto done; + } + len = sizeof (sock_in); + if (getsockname (newsock, (struct sockaddr *) &sock_in, &len) < 0) + { + debug_printf ("getsockname error"); + set_winsock_errno (); + closesocket (newsock); + goto done; + } + + /* For stream sockets, create a listener */ + if (type == SOCK_STREAM) + listen (newsock, 2); + + /* create a connecting socket */ + outsock = socket (AF_INET, type, 0); + if (outsock == INVALID_SOCKET) + { + debug_printf ("second socket call failed"); + set_winsock_errno (); + closesocket (newsock); + goto done; + } + + /* For datagram sockets, bind the 2nd socket to an unused address, too */ + if (type == SOCK_DGRAM) + { + sock_out.sin_family = AF_INET; + sock_out.sin_port = 0; + sock_out.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + if (bind (outsock, (struct sockaddr *) &sock_out, sizeof (sock_out)) < 0) + { + debug_printf ("bind failed"); + set_winsock_errno (); + closesocket (newsock); + closesocket (outsock); + goto done; + } + len = sizeof (sock_out); + if (getsockname (outsock, (struct sockaddr *) &sock_out, &len) < 0) + { + debug_printf ("getsockname error"); + set_winsock_errno (); + closesocket (newsock); + closesocket (outsock); + goto done; + } + } + + /* Force IP address to loopback */ + sock_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + if (type == SOCK_DGRAM) + sock_out.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + /* Do a connect */ + if (connect (outsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0) + { + debug_printf ("connect error"); + set_winsock_errno (); + closesocket (newsock); + closesocket (outsock); + goto done; + } + + if (type == SOCK_STREAM) + { + /* For stream sockets, accept the connection and close the listener */ + len = sizeof (sock_in); + insock = accept (newsock, (struct sockaddr *) &sock_in, &len); + if (insock == INVALID_SOCKET) + { + debug_printf ("accept error"); + set_winsock_errno (); + closesocket (newsock); + closesocket (outsock); + goto done; + } + closesocket (newsock); + } + else + { + /* For datagram sockets, connect the 2nd socket */ + if (connect (newsock, (struct sockaddr *) &sock_out, + sizeof (sock_out)) < 0) + { + debug_printf ("connect error"); + set_winsock_errno (); + closesocket (newsock); + closesocket (outsock); + goto done; + } + insock = newsock; + } + + { + cygheap_fdnew sb0; + const device *dev; + + if (family == AF_INET) + dev = (type == SOCK_STREAM ? tcp_dev : udp_dev); + else + dev = (type == SOCK_STREAM ? stream_dev : dgram_dev); + + if (sb0 >= 0 && fdsock (sb0, dev, insock)) + { + ((fhandler_socket *) sb0)->set_sun_path (""); + ((fhandler_socket *) sb0)->set_addr_family (family); + ((fhandler_socket *) sb0)->set_socket_type (type); + ((fhandler_socket *) sb0)->connect_state (connected); + if (family == AF_LOCAL && type == SOCK_STREAM) + ((fhandler_socket *) sb0)->af_local_set_sockpair_cred (); + + cygheap_fdnew sb1 (sb0, false); + + if (sb1 >= 0 && fdsock (sb1, dev, outsock)) + { + ((fhandler_socket *) sb1)->set_sun_path (""); + ((fhandler_socket *) sb1)->set_addr_family (family); + ((fhandler_socket *) sb1)->set_socket_type (type); + ((fhandler_socket *) sb1)->connect_state (connected); + if (family == AF_LOCAL && type == SOCK_STREAM) + ((fhandler_socket *) sb1)->af_local_set_sockpair_cred (); + + sb[0] = sb0; + sb[1] = sb1; + res = 0; + } + } + + if (res == -1) + { + closesocket (insock); + closesocket (outsock); + } + } + +done: + syscall_printf ("%d = socketpair (...)", res); + return res; +} + +/* sethostent: standards? */ +extern "C" void +sethostent (int) +{ +} + +/* endhostent: standards? */ +extern "C" void +endhostent (void) +{ +} + +/* exported as recvmsg: standards? */ +extern "C" int +cygwin_recvmsg (int fd, struct msghdr *msg, int flags) +{ + int res; + sig_dispatch_pending (); + + fhandler_socket *fh = get (fd); + + myfault efault; + if (efault.faulted (EFAULT) || !fh) + res = -1; + else + { + res = check_iovec_for_read (msg->msg_iov, msg->msg_iovlen); + if (res > 0) + res = fh->recvmsg (msg, flags, res); // res == iovec tot + } + + syscall_printf ("%d = recvmsg (%d, %p, %x)", res, fd, msg, flags); + return res; +} + +/* exported as sendmsg: standards? */ +extern "C" int +cygwin_sendmsg (int fd, const struct msghdr *msg, int flags) +{ + int res; + sig_dispatch_pending (); + + fhandler_socket *fh = get (fd); + + myfault efault; + if (efault.faulted (EFAULT) || !fh) + res = -1; + else + { + res = check_iovec_for_write (msg->msg_iov, msg->msg_iovlen); + res = fh->sendmsg (msg, flags, res); // res == iovec tot + } + + syscall_printf ("%d = sendmsg (%d, %p, %x)", res, fd, msg, flags); + return res; +} + +/* This is from the BIND 4.9.4 release, modified to compile by itself */ + +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#define IN6ADDRSZ 16 +#define INADDRSZ 4 +#define INT16SZ 2 + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton4 (const char *src, u_char *dst) +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + u_char tmp[INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') + { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) + { + u_int ret = *tp * 10 + (pch - digits); + + if (ret > 255) + return (0); + *tp = ret; + if (! saw_digit) + { + if (++octets > 4) + return (0); + saw_digit = 1; + } + } + else if (ch == '.' && saw_digit) + { + if (octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } + else + return (0); + } + if (octets < 4) + return (0); + + memcpy(dst, tmp, INADDRSZ); + return (1); +} + +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton6 (const char *src, u_char *dst) +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + u_int val; + + memset((tp = tmp), 0, IN6ADDRSZ); + endp = tp + IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + saw_xdigit = 0; + val = 0; + while ((ch = *src++) != '\0') + { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) + { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return (0); + saw_xdigit = 1; + continue; + } + if (ch == ':') + { + curtok = src; + if (!saw_xdigit) + { + if (colonp) + return (0); + colonp = tp; + continue; + } + if (tp + INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0) + { + tp += INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (saw_xdigit) + { + if (tp + INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + } + if (colonp != NULL) + { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + for (i = 1; i <= n; i++) + { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return (0); + + memcpy(dst, tmp, IN6ADDRSZ); + return (1); +} + +/* int + * inet_pton(af, src, dst) + * convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * return: + * 1 if the address was valid for the specified address family + * 0 if the address wasn't valid (`dst' is untouched in this case) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * author: + * Paul Vixie, 1996. + */ +extern "C" int +cygwin_inet_pton (int af, const char *src, void *dst) +{ + switch (af) + { + case AF_INET: + return (inet_pton4(src, (u_char *) dst)); + case AF_INET6: + return (inet_pton6(src, (u_char *) dst)); + default: + errno = EAFNOSUPPORT; + return (-1); + } + /* NOTREACHED */ +} + +/* const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address, more or less like inet_ntoa() + * return: + * `dst' (as a const) + * notes: + * (1) uses no statics + * (2) takes a u_char* not an in_addr as input + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop4 (const u_char *src, char *dst, size_t size) +{ + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[sizeof "255.255.255.255"]; + + __small_sprintf(tmp, fmt, src[0], src[1], src[2], src[3]); + if (strlen(tmp) > size) + { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} + +/* const char * + * inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop6 (const u_char *src, char *dst, size_t size) +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; + struct { int base, len; } best, cur; + u_int words[IN6ADDRSZ / INT16SZ]; + int i; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, 0, sizeof words); + for (i = 0; i < IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + cur.base = -1; + for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) + { + if (words[i] == 0) + { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } + else + { + if (cur.base != -1) + { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) + { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) + { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && i < (best.base + best.len)) + { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && + (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) + { + if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) + return (NULL); + tp += strlen(tp); + break; + } + __small_sprintf(tp, "%x", words[i]); + tp += strlen(tp); + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t) (tp - tmp) > size) + { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} + +/* char * + * inet_ntop(af, src, dst, size) + * convert a network format address to presentation format. + * return: + * pointer to presentation format address (`dst'), or NULL (see errno). + * author: + * Paul Vixie, 1996. + */ +extern "C" const char * +cygwin_inet_ntop (int af, const void *src, char *dst, size_t size) +{ + switch (af) + { + case AF_INET: + return (inet_ntop4((const u_char *) src, dst, size)); + case AF_INET6: + return (inet_ntop6((const u_char *) src, dst, size)); + default: + errno = EAFNOSUPPORT; + return (NULL); + } + /* NOTREACHED */ +} + +/* W. Richard STEVENS libgai implementation, slightly tweaked for inclusion + into Cygwin as pure IPv4 replacement. Please note that the code is + kept intact as much as possible. Especially the IPv6 and AF_UNIX code + is kept in, even though we can support neither of them. Please don't + activate them, they won't work correctly. */ + +#define IPv4 +#undef IPv6 +#undef UNIXdomain + +#undef HAVE_SOCKADDR_SA_LEN +#define gethostbyname2(host,family) cygwin_gethostbyname((host)) + +#define AI_CLONE 0x8000 /* Avoid collision with AI_ values in netdb.h */ + +/* + * Create and fill in an addrinfo{}. + */ + +/* include ga_aistruct1 */ +static int +ga_aistruct (struct addrinfo ***paipnext, const struct addrinfo *hintsp, + const void *addr, int family) +{ + struct addrinfo *ai; + + if ((ai = (struct addrinfo *) calloc (1, sizeof (struct addrinfo))) == NULL) + return (EAI_MEMORY); + ai->ai_next = NULL; + ai->ai_canonname = NULL; + **paipnext = ai; + *paipnext = &ai->ai_next; + + if ((ai->ai_socktype = hintsp->ai_socktype) == 0) + ai->ai_flags |= AI_CLONE; + + ai->ai_protocol = hintsp->ai_protocol; +/* end ga_aistruct1 */ + +/* include ga_aistruct2 */ + switch ((ai->ai_family = family)) + { +#ifdef IPv4 + case AF_INET: + { + struct sockaddr_in *sinptr; + + /* 4allocate sockaddr_in{} and fill in all but port */ + if ((sinptr = (struct sockaddr_in *) + calloc (1, sizeof (struct sockaddr_in))) == NULL) + return (EAI_MEMORY); +#ifdef HAVE_SOCKADDR_SA_LEN + sinptr->sin_len = sizeof (struct sockaddr_in); +#endif + sinptr->sin_family = AF_INET; + memcpy (&sinptr->sin_addr, addr, sizeof (struct in_addr)); + ai->ai_addr = (struct sockaddr *) sinptr; + ai->ai_addrlen = sizeof (struct sockaddr_in); + break; + } +#endif /* IPV4 */ +#ifdef IPv6 + case AF_INET6: + { + struct sockaddr_in6 *sin6ptr; + + /* 4allocate sockaddr_in6{} and fill in all but port */ + if ((sin6ptr = calloc (1, sizeof (struct sockaddr_in6))) == NULL) + return (EAI_MEMORY); +#ifdef HAVE_SOCKADDR_SA_LEN + sin6ptr->sin6_len = sizeof (struct sockaddr_in6); +#endif + sin6ptr->sin6_family = AF_INET6; + memcpy (&sin6ptr->sin6_addr, addr, sizeof (struct in6_addr)); + ai->ai_addr = (struct sockaddr *) sin6ptr; + ai->ai_addrlen = sizeof (struct sockaddr_in6); + break; + } +#endif /* IPV6 */ +#ifdef UNIXdomain + case AF_LOCAL: + { + struct sockaddr_un *unp; + + /* 4allocate sockaddr_un{} and fill in */ +/* *INDENT-OFF* */ + if (strlen(addr) >= sizeof(unp->sun_path)) + return(EAI_SERVICE); + if ( (unp = calloc(1, sizeof(struct sockaddr_un))) == NULL) + return(EAI_MEMORY); +/* *INDENT-ON* */ + unp->sun_family = AF_LOCAL; + strcpy (unp->sun_path, addr); +#ifdef HAVE_SOCKADDR_SA_LEN + unp->sun_len = SUN_LEN (unp); +#endif + ai->ai_addr = (struct sockaddr *) unp; + ai->ai_addrlen = sizeof (struct sockaddr_un); + if (hintsp->ai_flags & AI_PASSIVE) + unlink (unp->sun_path); /* OK if this fails */ + break; + } +#endif /* UNIXDOMAIN */ + } + return (0); +} + +/* end ga_aistruct2 */ + +/* + * Clone a new addrinfo structure from an existing one. + */ + +/* include ga_clone */ +static struct addrinfo * +ga_clone (struct addrinfo *ai) +{ + struct addrinfo *nai; + + if ((nai = (struct addrinfo *) calloc (1, sizeof (struct addrinfo))) == NULL) + return (NULL); + + nai->ai_next = ai->ai_next; + ai->ai_next = nai; + + nai->ai_flags = 0; /* make sure AI_CLONE is off */ + nai->ai_family = ai->ai_family; + nai->ai_socktype = ai->ai_socktype; + nai->ai_protocol = ai->ai_protocol; + nai->ai_canonname = NULL; + nai->ai_addrlen = ai->ai_addrlen; + if ((nai->ai_addr = (struct sockaddr *) malloc (ai->ai_addrlen)) == NULL) + return (NULL); + memcpy (nai->ai_addr, ai->ai_addr, ai->ai_addrlen); + + return (nai); +} + +/* end ga_clone */ + +/* + * Basic error checking of flags, family, socket type, and protocol. + */ + +/* include ga_echeck */ +static int +ga_echeck (const char *hostname, const char *servname, + int flags, int family, int socktype, int protocol) +{ + if (flags & ~(AI_PASSIVE | AI_CANONNAME)) + return (EAI_BADFLAGS); /* unknown flag bits */ + + if (hostname == NULL || hostname[0] == '\0') + { + if (servname == NULL || servname[0] == '\0') + return (EAI_NONAME); /* host or service must be specified */ + } + + switch (family) + { + case AF_UNSPEC: + break; +#ifdef IPv4 + case AF_INET: + if (socktype != 0 && + (socktype != SOCK_STREAM && + socktype != SOCK_DGRAM && socktype != SOCK_RAW)) + return (EAI_SOCKTYPE); /* invalid socket type */ + break; +#endif +#ifdef IPv6 + case AF_INET6: + if (socktype != 0 && + (socktype != SOCK_STREAM && + socktype != SOCK_DGRAM && socktype != SOCK_RAW)) + return (EAI_SOCKTYPE); /* invalid socket type */ + break; +#endif +#ifdef UNIXdomain + case AF_LOCAL: + if (socktype != 0 && + (socktype != SOCK_STREAM && socktype != SOCK_DGRAM)) + return (EAI_SOCKTYPE); /* invalid socket type */ + break; +#endif + default: + return (EAI_FAMILY); /* unknown protocol family */ + } + return (0); +} + +/* end ga_echeck */ + +struct search { + const char *host; /* hostname or address string */ + int family; /* AF_xxx */ +}; + +/* + * Set up the search[] array with the hostnames and address families + * that we are to look up. + */ + +/* include ga_nsearch1 */ +static int +ga_nsearch (const char *hostname, const struct addrinfo *hintsp, + struct search *search) +{ + int nsearch = 0; + + if (hostname == NULL || hostname[0] == '\0') + { + if (hintsp->ai_flags & AI_PASSIVE) + { + /* 4no hostname and AI_PASSIVE: implies wildcard bind */ + switch (hintsp->ai_family) + { +#ifdef IPv4 + case AF_INET: + search[nsearch].host = "0.0.0.0"; + search[nsearch].family = AF_INET; + nsearch++; + break; +#endif +#ifdef IPv6 + case AF_INET6: + search[nsearch].host = "0::0"; + search[nsearch].family = AF_INET6; + nsearch++; + break; +#endif + case AF_UNSPEC: +#ifdef IPv6 + search[nsearch].host = "0::0"; /* IPv6 first, then IPv4 */ + search[nsearch].family = AF_INET6; + nsearch++; +#endif +#ifdef IPv4 + search[nsearch].host = "0.0.0.0"; + search[nsearch].family = AF_INET; + nsearch++; +#endif + break; + } +/* end ga_nsearch1 */ +/* include ga_nsearch2 */ + } + else + { + /* 4no host and not AI_PASSIVE: connect to local host */ + switch (hintsp->ai_family) + { +#ifdef IPv4 + case AF_INET: + search[nsearch].host = "localhost"; /* 127.0.0.1 */ + search[nsearch].family = AF_INET; + nsearch++; + break; +#endif +#ifdef IPv6 + case AF_INET6: + search[nsearch].host = "0::1"; + search[nsearch].family = AF_INET6; + nsearch++; + break; +#endif + case AF_UNSPEC: +#ifdef IPv6 + search[nsearch].host = "0::1"; /* IPv6 first, then IPv4 */ + search[nsearch].family = AF_INET6; + nsearch++; +#endif +#ifdef IPv4 + search[nsearch].host = "localhost"; + search[nsearch].family = AF_INET; + nsearch++; +#endif + break; + } + } +/* end ga_nsearch2 */ +/* include ga_nsearch3 */ + } + else + { /* host is specified */ + switch (hintsp->ai_family) + { +#ifdef IPv4 + case AF_INET: + search[nsearch].host = hostname; + search[nsearch].family = AF_INET; + nsearch++; + break; +#endif +#ifdef IPv6 + case AF_INET6: + search[nsearch].host = hostname; + search[nsearch].family = AF_INET6; + nsearch++; + break; +#endif + case AF_UNSPEC: +#ifdef IPv6 + search[nsearch].host = hostname; + search[nsearch].family = AF_INET6; /* IPv6 first */ + nsearch++; +#endif +#ifdef IPv4 + search[nsearch].host = hostname; + search[nsearch].family = AF_INET; /* then IPv4 */ + nsearch++; +#endif + break; + } + } + if (nsearch < 1 || nsearch > 2) + return -1; + return (nsearch); +} + +/* end ga_nsearch3 */ + +/* + * Go through all the addrinfo structures, checking for a match of the + * socket type and filling in the socket type, and then the port number + * in the corresponding socket address structures. + * + * The AI_CLONE flag works as follows. Consider a multihomed host with + * two IP addresses and no socket type specified by the caller. After + * the "host" search there are two addrinfo structures, one per IP address. + * Assuming a service supported by both TCP and UDP (say the daytime + * service) we need to return *four* addrinfo structures: + * IP#1, SOCK_STREAM, TCP port, + * IP#1, SOCK_DGRAM, UDP port, + * IP#2, SOCK_STREAM, TCP port, + * IP#2, SOCK_DGRAM, UDP port. + * To do this, when the "host" loop creates an addrinfo structure, if the + * caller has not specified a socket type (hintsp->ai_socktype == 0), the + * AI_CLONE flag is set. When the following function finds an entry like + * this it is handled as follows: If the entry's ai_socktype is still 0, + * this is the first use of the structure, and the ai_socktype field is set. + * But, if the entry's ai_socktype is nonzero, then we clone a new addrinfo + * structure and set it's ai_socktype to the new value. Although we only + * need two socket types today (SOCK_STREAM and SOCK_DGRAM) this algorithm + * will handle any number. Also notice that Posix.1g requires all socket + * types to be nonzero. + */ + +/* include ga_port */ +static int +ga_port (struct addrinfo *aihead, int port, int socktype) + /* port must be in network byte order */ +{ + int nfound = 0; + struct addrinfo *ai; + + for (ai = aihead; ai != NULL; ai = ai->ai_next) + { + if (ai->ai_flags & AI_CLONE) + { + if (ai->ai_socktype != 0) + { + if ((ai = ga_clone (ai)) == NULL) + return (-1); /* memory allocation error */ + /* ai points to newly cloned entry, which is what we want */ + } + } + else if (ai->ai_socktype != socktype) + continue; /* ignore if mismatch on socket type */ + + ai->ai_socktype = socktype; + + switch (ai->ai_family) + { +#ifdef IPv4 + case AF_INET: + ((struct sockaddr_in *) ai->ai_addr)->sin_port = port; + nfound++; + break; +#endif +#ifdef IPv6 + case AF_INET6: + ((struct sockaddr_in6 *) ai->ai_addr)->sin6_port = port; + nfound++; + break; +#endif + } + } + return (nfound); +} + +/* end ga_port */ + +/* + * This function handles the service string. + */ + +/* include ga_serv */ +static int +ga_serv (struct addrinfo *aihead, const struct addrinfo *hintsp, + const char *serv) +{ + int port, rc, nfound; + struct servent *sptr; + + nfound = 0; + if (isdigit (serv[0])) + { /* check for port number string first */ + port = htons (atoi (serv)); + if (hintsp->ai_socktype) + { + /* 4caller specifies socket type */ + if ((rc = ga_port (aihead, port, hintsp->ai_socktype)) < 0) + return (EAI_MEMORY); + nfound += rc; + } + else + { + /* 4caller does not specify socket type */ + if ((rc = ga_port (aihead, port, SOCK_STREAM)) < 0) + return (EAI_MEMORY); + nfound += rc; + if ((rc = ga_port (aihead, port, SOCK_DGRAM)) < 0) + return (EAI_MEMORY); + nfound += rc; + } + } + else + { + /* 4try service name, TCP then UDP */ + if (hintsp->ai_socktype == 0 || hintsp->ai_socktype == SOCK_STREAM) + { + if ((sptr = cygwin_getservbyname (serv, "tcp")) != NULL) + { + if ((rc = ga_port (aihead, sptr->s_port, SOCK_STREAM)) < 0) + return (EAI_MEMORY); + nfound += rc; + } + } + if (hintsp->ai_socktype == 0 || hintsp->ai_socktype == SOCK_DGRAM) + { + if ((sptr = cygwin_getservbyname (serv, "udp")) != NULL) + { + if ((rc = ga_port (aihead, sptr->s_port, SOCK_DGRAM)) < 0) + return (EAI_MEMORY); + nfound += rc; + } + } + } + + if (nfound == 0) + { + if (hintsp->ai_socktype == 0) + return (EAI_NONAME); /* all calls to getservbyname() failed */ + else + return (EAI_SERVICE); /* service not supported for socket type */ + } + return (0); +} + +/* end ga_serv */ + +#ifdef UNIXdomain +/* include ga_unix */ +static int +ga_unix (const char *path, struct addrinfo *hintsp, struct addrinfo **result) +{ + int rc; + struct addrinfo *aihead, **aipnext; + + aihead = NULL; + aipnext = &aihead; + + if (hintsp->ai_family != AF_UNSPEC && hintsp->ai_family != AF_LOCAL) + return (EAI_ADDRFAMILY); + + if (hintsp->ai_socktype == 0) + { + /* 4no socket type specified: return stream then dgram */ + hintsp->ai_socktype = SOCK_STREAM; + if ((rc = ga_aistruct (&aipnext, hintsp, path, AF_LOCAL)) != 0) + return (rc); + hintsp->ai_socktype = SOCK_DGRAM; + } + + if ((rc = ga_aistruct (&aipnext, hintsp, path, AF_LOCAL)) != 0) + return (rc); + + if (hintsp->ai_flags & AI_CANONNAME) + { + struct utsname myname; + + if (uname (&myname) < 0) + return (EAI_SYSTEM); + if ((aihead->ai_canonname = strdup (myname.nodename)) == NULL) + return (EAI_MEMORY); + } + + *result = aihead; /* pointer to first structure in linked list */ + return (0); +} + +/* end ga_unix */ +#endif /* UNIXdomain */ + +/* include gn_ipv46 */ +static int +gn_ipv46 (char *host, size_t hostlen, char *serv, size_t servlen, + void *aptr, size_t alen, int family, int port, int flags) +{ + char *ptr; + struct hostent *hptr; + struct servent *sptr; + + if (host && hostlen > 0) + { + if (flags & NI_NUMERICHOST) + { + if (cygwin_inet_ntop (family, aptr, host, hostlen) == NULL) + return (1); + } + else + { + hptr = cygwin_gethostbyaddr ((const char *) aptr, alen, family); + if (hptr != NULL && hptr->h_name != NULL) + { + if (flags & NI_NOFQDN) + { + if ((ptr = strchr (hptr->h_name, '.')) != NULL) + *ptr = 0; /* overwrite first dot */ + } + //snprintf (host, hostlen, "%s", hptr->h_name); + *host = '\0'; + strncat (host, hptr->h_name, hostlen - 1); + } + else + { + if (flags & NI_NAMEREQD) + return (1); + if (cygwin_inet_ntop (family, aptr, host, hostlen) == NULL) + return (1); + } + } + } + + if (serv && servlen > 0) + { + if (flags & NI_NUMERICSERV) + { + //snprintf (serv, servlen, "%d", ntohs (port)); + char buf[32]; + __small_sprintf (buf, "%d", ntohs (port)); + *serv = '\0'; + strncat (serv, buf, servlen - 1); + } + else + { + sptr = cygwin_getservbyport (port, (flags & NI_DGRAM) ? "udp" : NULL); + if (sptr != NULL && sptr->s_name != NULL) + { + //snprintf (serv, servlen, "%s", sptr->s_name); + *serv = '\0'; + strncat (serv, sptr->s_name, servlen - 1); + } + else + { + //snprintf (serv, servlen, "%d", ntohs (port)); + char buf[32]; + __small_sprintf (buf, "%d", ntohs (port)); + *serv = '\0'; + strncat (serv, buf, servlen - 1); + } + } + } + return (0); +} + +/* end gn_ipv46 */ + +/* include freeaddrinfo */ +void +ipv4_freeaddrinfo (struct addrinfo *aihead) +{ + struct addrinfo *ai, *ainext; + + for (ai = aihead; ai != NULL; ai = ainext) + { + if (ai->ai_addr != NULL) + free (ai->ai_addr); /* socket address structure */ + + if (ai->ai_canonname != NULL) + free (ai->ai_canonname); + + ainext = ai->ai_next; /* can't fetch ai_next after free() */ + free (ai); /* the addrinfo{} itself */ + } +} + +/* end freeaddrinfo */ + +/* include ga1 */ + +int +ipv4_getaddrinfo (const char *hostname, const char *servname, + const struct addrinfo *hintsp, struct addrinfo **result) +{ + int rc, error, nsearch; + char **ap, *canon; + struct hostent *hptr; + struct search search[3], *sptr; + struct addrinfo hints, *aihead, **aipnext; + + /* + * If we encounter an error we want to free() any dynamic memory + * that we've allocated. This is our hack to simplify the code. + */ +#define error(e) { error = (e); goto bad; } + + aihead = NULL; /* initialize automatic variables */ + aipnext = &aihead; + canon = NULL; + + if (hintsp == NULL) + { + bzero (&hints, sizeof (hints)); + hints.ai_family = AF_UNSPEC; + } + else + hints = *hintsp; /* struct copy */ + + /* 4first some basic error checking */ + if ((rc = ga_echeck (hostname, servname, hints.ai_flags, hints.ai_family, + hints.ai_socktype, hints.ai_protocol)) != 0) + error (rc); + +#ifdef UNIXdomain + /* 4special case Unix domain first */ + if (hostname != NULL && + (strcmp (hostname, "/local") == 0 || strcmp (hostname, "/unix") == 0) && + (servname != NULL && servname[0] == '/')) + return (ga_unix (servname, &hints, result)); +#endif +/* end ga1 */ + +/* include ga3 */ + /* 4remainder of function for IPv4/IPv6 */ + nsearch = ga_nsearch (hostname, &hints, &search[0]); + if (nsearch == -1) + error (EAI_FAMILY); + for (sptr = &search[0]; sptr < &search[nsearch]; sptr++) + { +#ifdef IPv4 + /* 4check for an IPv4 dotted-decimal string */ + if (isdigit (sptr->host[0])) + { + struct in_addr inaddr; + + if (inet_pton4 (sptr->host, (u_char *) &inaddr) == 1) + { + if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET) + error (EAI_ADDRFAMILY); + if (sptr->family != AF_INET) + continue; /* ignore */ + rc = ga_aistruct (&aipnext, &hints, &inaddr, AF_INET); + if (rc != 0) + error (rc); + continue; + } + } +#endif + +#ifdef IPv6 + /* 4check for an IPv6 hex string */ + if ((isxdigit (sptr->host[0]) || sptr->host[0] == ':') && + (strchr (sptr->host, ':') != NULL)) + { + struct in6_addr in6addr; + + if (inet_pton6 (sptr->host, &in6addr) == 1) + { + if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6) + error (EAI_ADDRFAMILY); + if (sptr->family != AF_INET6) + continue; /* ignore */ + rc = ga_aistruct (&aipnext, &hints, &in6addr, AF_INET6); + if (rc != 0) + error (rc); + continue; + } + } +#endif +/* end ga3 */ +/* include ga4 */ +#ifdef IPv6 + /* 4remainder of for() to look up hostname */ + if ((_res.options & RES_INIT) == 0) + res_init (); /* need this to set _res.options */ +#endif + + if (nsearch == 2) + { +#ifdef IPv6 + _res.options &= ~RES_USE_INET6; +#endif + hptr = gethostbyname2 (sptr->host, sptr->family); + } + else + { +#ifdef IPv6 + if (sptr->family == AF_INET6) + _res.options |= RES_USE_INET6; + else + _res.options &= ~RES_USE_INET6; +#endif + hptr = gethostbyname (sptr->host); + } + if (hptr == NULL) + { + if (nsearch == 2) + continue; /* failure OK if multiple searches */ + + switch (h_errno) + { + case HOST_NOT_FOUND: + error (EAI_NONAME); + case TRY_AGAIN: + error (EAI_AGAIN); + case NO_RECOVERY: + error (EAI_FAIL); + case NO_DATA: + error (EAI_NODATA); + default: + error (EAI_NONAME); + } + } + + /* 4check for address family mismatch if one specified */ + if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype) + error (EAI_ADDRFAMILY); + + /* 4save canonical name first time */ + if (hostname != NULL && hostname[0] != '\0' && + (hints.ai_flags & AI_CANONNAME) && canon == NULL) + { + if ((canon = strdup (hptr->h_name)) == NULL) + error (EAI_MEMORY); + } + + /* 4create one addrinfo{} for each returned address */ + for (ap = hptr->h_addr_list; *ap != NULL; ap++) + { + rc = ga_aistruct (&aipnext, &hints, *ap, hptr->h_addrtype); + if (rc != 0) + error (rc); + } + } + if (aihead == NULL) + error (EAI_NONAME); /* nothing found */ +/* end ga4 */ + +/* include ga5 */ + /* 4return canonical name */ + if (hostname != NULL && hostname[0] != '\0' && + hints.ai_flags & AI_CANONNAME) + { + if (canon != NULL) + aihead->ai_canonname = canon; /* strdup'ed earlier */ + else + { + if ((aihead->ai_canonname = strdup (search[0].host)) == NULL) + error (EAI_MEMORY); + } + } + + /* 4now process the service name */ + if (servname != NULL && servname[0] != '\0') + { + if ((rc = ga_serv (aihead, &hints, servname)) != 0) + error (rc); + } + + *result = aihead; /* pointer to first structure in linked list */ + return (0); + +bad: + ipv4_freeaddrinfo (aihead); /* free any alloc'ed memory */ + return (error); +} + +/* end ga5 */ + +/* include getnameinfo */ +int +ipv4_getnameinfo (const struct sockaddr *sa, socklen_t salen, + char *host, size_t hostlen, + char *serv, size_t servlen, int flags) +{ + + switch (sa->sa_family) + { +#ifdef IPv4 + case AF_INET: + { + struct sockaddr_in *sain = (struct sockaddr_in *) sa; + + return (gn_ipv46 (host, hostlen, serv, servlen, + &sain->sin_addr, sizeof (struct in_addr), + AF_INET, sain->sin_port, flags)); + } +#endif + +#ifdef IPv6 + case AF_INET6: + { + struct sockaddr_in6 *sain = (struct sockaddr_in6 *) sa; + + return (gn_ipv46 (host, hostlen, serv, servlen, + &sain->sin6_addr, sizeof (struct in6_addr), + AF_INET6, sain->sin6_port, flags)); + } +#endif + +#ifdef UNIXdomain + case AF_LOCAL: + { + struct sockaddr_un *un = (struct sockaddr_un *) sa; + + if (hostlen > 0) + snprintf (host, hostlen, "%s", "/local"); + if (servlen > 0) + snprintf (serv, servlen, "%s", un->sun_path); + return (0); + } +#endif + + default: + return (1); + } +} + +/* end getnameinfo */ + +/* Start of cygwin specific wrappers around the gai functions. */ + +struct gai_errmap_t +{ + int w32_errval; + const char *errtxt; +}; + +static gai_errmap_t gai_errmap[] = +{ + {0, "Success"}, + {0, "Address family for hostname not supported"}, + {WSATRY_AGAIN, "Temporary failure in name resolution"}, + {WSAEINVAL, "Invalid value for ai_flags"}, + {WSANO_RECOVERY, "Non-recoverable failure in name resolution"}, + {WSAEAFNOSUPPORT, "ai_family not supported"}, + {WSA_NOT_ENOUGH_MEMORY, "Memory allocation failure"}, + {WSANO_DATA, "No address associated with hostname"}, + {WSAHOST_NOT_FOUND, "hostname nor servname provided, or not known"}, + {WSATYPE_NOT_FOUND, "servname not supported for ai_socktype"}, + {WSAESOCKTNOSUPPORT, "ai_socktype not supported"}, + {0, "System error returned in errno"}, + {0, "Invalid value for hints"}, + {0, "Resolved protocol is unknown"} +}; + +extern "C" const char * +cygwin_gai_strerror (int err) +{ + if (err >= 0 && err < EAI_MAX) + return gai_errmap[err].errtxt; + return "Unknown error"; +} + +static int +w32_to_gai_err (int w32_err) +{ + if (w32_err >= WSABASEERR) + for (int i = 0; i < EAI_MAX; ++i) + if (gai_errmap[i].w32_errval == w32_err) + return i; + return w32_err; +} + +/* We can't use autoload here because we don't know where the functions + are loaded from. On Win2K, the functions are available in the + ipv6 technology preview lib called wship6.dll, in XP and above they + are implemented in ws2_32.dll. For older systems we use the ipv4-only + version above. */ + +static void (WINAPI *freeaddrinfo)(const struct addrinfo *); +static int (WINAPI *getaddrinfo)(const char *, const char *, + const struct addrinfo *, + struct addrinfo **); +static int (WINAPI *getnameinfo)(const struct sockaddr *, socklen_t, + char *, size_t, char *, size_t, int); +static bool +get_ipv6_funcs (HMODULE lib) +{ + return ((freeaddrinfo = (void (WINAPI *)(const struct addrinfo *)) + GetProcAddress(lib, "freeaddrinfo")) + && (getaddrinfo = (int (WINAPI *)(const char *, const char *, + const struct addrinfo *, + struct addrinfo **)) + GetProcAddress(lib, "getaddrinfo")) + && (getnameinfo = (int (WINAPI *)(const struct sockaddr *, + socklen_t, char *, size_t, + char *, size_t, int)) + GetProcAddress(lib, "getnameinfo"))); +} + +static NO_COPY muto load_ipv6_guard; +static bool ipv6_inited = false; +#define load_ipv6() if (!ipv6_inited) load_ipv6_funcs (); + +static void +load_ipv6_funcs () +{ + + char lib_name[CYG_MAX_PATH]; + size_t len; + HMODULE lib; + + load_ipv6_guard.init ("klog_guard")->acquire (); + if (ipv6_inited) + goto out; + WSAGetLastError (); /* Kludge. Enforce WSAStartup call. */ + if (GetSystemDirectory (lib_name, CYG_MAX_PATH)) + { + len = strlen (lib_name); + strcpy (lib_name + len, "\\ws2_32.dll"); + if ((lib = LoadLibrary (lib_name))) + { + if (get_ipv6_funcs (lib)) + goto out; + FreeLibrary (lib); + } + strcpy (lib_name + len, "\\wship6.dll"); + if ((lib = LoadLibrary (lib_name))) + { + if (get_ipv6_funcs (lib)) + goto out; + FreeLibrary (lib); + } + freeaddrinfo = NULL; + getaddrinfo = NULL; + getnameinfo = NULL; + } +out: + ipv6_inited = true; + load_ipv6_guard.release (); +} + +extern "C" void +cygwin_freeaddrinfo (struct addrinfo *addr) +{ + myfault efault; + if (efault.faulted (EFAULT)) + return; + load_ipv6 (); + if (freeaddrinfo) + freeaddrinfo (addr); + else + ipv4_freeaddrinfo (addr); +} + +extern "C" int +cygwin_getaddrinfo (const char *hostname, const char *servname, + const struct addrinfo *hints, struct addrinfo **res) +{ + myfault efault; + if (efault.faulted (EFAULT)) + return EAI_SYSTEM; + load_ipv6 (); + if (getaddrinfo) + return w32_to_gai_err (getaddrinfo (hostname, servname, hints, res)); + return ipv4_getaddrinfo (hostname, servname, hints, res); +} + +extern "C" int +cygwin_getnameinfo (const struct sockaddr *sa, socklen_t salen, + char *host, size_t hostlen, char *serv, + size_t servlen, int flags) +{ + myfault efault; + if (efault.faulted (EFAULT)) + return EAI_SYSTEM; + load_ipv6 (); + if (getnameinfo) + { + /* When the incoming port number is set to 0, Winsock's getnameinfo + returns with error WSAENO_DATA instead of simply ignoring the port. + To avoid this strange behaviour, we check manually, if the port number + is 0. If so, set the NI_NUMERICSERV flag to avoid this problem. */ + switch (sa->sa_family) + { + case AF_INET: + if (((struct sockaddr_in *) sa)->sin_port == 0) + flags |= NI_NUMERICSERV; + break; + case AF_INET6: + if (((struct sockaddr_in6 *) sa)->sin6_port == 0) + flags |= NI_NUMERICSERV; + break; + } + int ret = w32_to_gai_err (getnameinfo (sa, salen, host, hostlen, serv, + servlen, flags)); + if (ret) + set_winsock_errno (); + return ret; + } + return ipv4_getnameinfo (sa, salen, host, hostlen, serv, servlen, flags); +} + |