Removal of Unix dependency
This commit is contained in:
parent
1ecf94e7ba
commit
cfd453cca0
4
Makefile
4
Makefile
|
@ -13,8 +13,8 @@ OCAMLLDFLAGS = -g
|
||||||
|
|
||||||
all : native-code native-code-library byte-code-library top htdoc
|
all : native-code native-code-library byte-code-library top htdoc
|
||||||
|
|
||||||
LIBINSTALL_FILES = cpdf.a cpdf.cma cpdf.cmxa \
|
LIBINSTALL_FILES = cpdf.a cpdf.cma cpdf.cmxa libcpdf_stubs.a \
|
||||||
$(foreach x,$(MODS),$x.mli) $(foreach x,$(MODS),$x.cmi)
|
dllcpdf_stubs.* $(foreach x,$(MODS),$x.mli) $(foreach x,$(MODS),$x.cmi)
|
||||||
|
|
||||||
install : libinstall
|
install : libinstall
|
||||||
|
|
||||||
|
|
971
cpdfunix.ml
971
cpdfunix.ml
|
@ -87,322 +87,6 @@ exception Unix_error of error * string * string
|
||||||
let _ = Callback.register_exception "Unix.Unix_error"
|
let _ = Callback.register_exception "Unix.Unix_error"
|
||||||
(Unix_error(E2BIG, "", ""))
|
(Unix_error(E2BIG, "", ""))
|
||||||
|
|
||||||
external error_message : error -> string = "unix_error_message"
|
|
||||||
|
|
||||||
let () =
|
|
||||||
Printexc.register_printer
|
|
||||||
(function
|
|
||||||
| Unix_error (e, s, s') ->
|
|
||||||
let msg = match e with
|
|
||||||
| E2BIG -> "E2BIG"
|
|
||||||
| EACCES -> "EACCES"
|
|
||||||
| EAGAIN -> "EAGAIN"
|
|
||||||
| EBADF -> "EBADF"
|
|
||||||
| EBUSY -> "EBUSY"
|
|
||||||
| ECHILD -> "ECHILD"
|
|
||||||
| EDEADLK -> "EDEADLK"
|
|
||||||
| EDOM -> "EDOM"
|
|
||||||
| EEXIST -> "EEXIST"
|
|
||||||
| EFAULT -> "EFAULT"
|
|
||||||
| EFBIG -> "EFBIG"
|
|
||||||
| EINTR -> "EINTR"
|
|
||||||
| EINVAL -> "EINVAL"
|
|
||||||
| EIO -> "EIO"
|
|
||||||
| EISDIR -> "EISDIR"
|
|
||||||
| EMFILE -> "EMFILE"
|
|
||||||
| EMLINK -> "EMLINK"
|
|
||||||
| ENAMETOOLONG -> "ENAMETOOLONG"
|
|
||||||
| ENFILE -> "ENFILE"
|
|
||||||
| ENODEV -> "ENODEV"
|
|
||||||
| ENOENT -> "ENOENT"
|
|
||||||
| ENOEXEC -> "ENOEXEC"
|
|
||||||
| ENOLCK -> "ENOLCK"
|
|
||||||
| ENOMEM -> "ENOMEM"
|
|
||||||
| ENOSPC -> "ENOSPC"
|
|
||||||
| ENOSYS -> "ENOSYS"
|
|
||||||
| ENOTDIR -> "ENOTDIR"
|
|
||||||
| ENOTEMPTY -> "ENOTEMPTY"
|
|
||||||
| ENOTTY -> "ENOTTY"
|
|
||||||
| ENXIO -> "ENXIO"
|
|
||||||
| EPERM -> "EPERM"
|
|
||||||
| EPIPE -> "EPIPE"
|
|
||||||
| ERANGE -> "ERANGE"
|
|
||||||
| EROFS -> "EROFS"
|
|
||||||
| ESPIPE -> "ESPIPE"
|
|
||||||
| ESRCH -> "ESRCH"
|
|
||||||
| EXDEV -> "EXDEV"
|
|
||||||
| EWOULDBLOCK -> "EWOULDBLOCK"
|
|
||||||
| EINPROGRESS -> "EINPROGRESS"
|
|
||||||
| EALREADY -> "EALREADY"
|
|
||||||
| ENOTSOCK -> "ENOTSOCK"
|
|
||||||
| EDESTADDRREQ -> "EDESTADDRREQ"
|
|
||||||
| EMSGSIZE -> "EMSGSIZE"
|
|
||||||
| EPROTOTYPE -> "EPROTOTYPE"
|
|
||||||
| ENOPROTOOPT -> "ENOPROTOOPT"
|
|
||||||
| EPROTONOSUPPORT -> "EPROTONOSUPPORT"
|
|
||||||
| ESOCKTNOSUPPORT -> "ESOCKTNOSUPPORT"
|
|
||||||
| EOPNOTSUPP -> "EOPNOTSUPP"
|
|
||||||
| EPFNOSUPPORT -> "EPFNOSUPPORT"
|
|
||||||
| EAFNOSUPPORT -> "EAFNOSUPPORT"
|
|
||||||
| EADDRINUSE -> "EADDRINUSE"
|
|
||||||
| EADDRNOTAVAIL -> "EADDRNOTAVAIL"
|
|
||||||
| ENETDOWN -> "ENETDOWN"
|
|
||||||
| ENETUNREACH -> "ENETUNREACH"
|
|
||||||
| ENETRESET -> "ENETRESET"
|
|
||||||
| ECONNABORTED -> "ECONNABORTED"
|
|
||||||
| ECONNRESET -> "ECONNRESET"
|
|
||||||
| ENOBUFS -> "ENOBUFS"
|
|
||||||
| EISCONN -> "EISCONN"
|
|
||||||
| ENOTCONN -> "ENOTCONN"
|
|
||||||
| ESHUTDOWN -> "ESHUTDOWN"
|
|
||||||
| ETOOMANYREFS -> "ETOOMANYREFS"
|
|
||||||
| ETIMEDOUT -> "ETIMEDOUT"
|
|
||||||
| ECONNREFUSED -> "ECONNREFUSED"
|
|
||||||
| EHOSTDOWN -> "EHOSTDOWN"
|
|
||||||
| EHOSTUNREACH -> "EHOSTUNREACH"
|
|
||||||
| ELOOP -> "ELOOP"
|
|
||||||
| EOVERFLOW -> "EOVERFLOW"
|
|
||||||
| EUNKNOWNERR x -> Printf.sprintf "EUNKNOWNERR %d" x in
|
|
||||||
Some (Printf.sprintf "Unix.Unix_error(Unix.%s, %S, %S)" msg s s')
|
|
||||||
| _ -> None)
|
|
||||||
|
|
||||||
let handle_unix_error f arg =
|
|
||||||
try
|
|
||||||
f arg
|
|
||||||
with Unix_error(err, fun_name, arg) ->
|
|
||||||
prerr_string Sys.argv.(0);
|
|
||||||
prerr_string ": \"";
|
|
||||||
prerr_string fun_name;
|
|
||||||
prerr_string "\" failed";
|
|
||||||
if String.length arg > 0 then begin
|
|
||||||
prerr_string " on \"";
|
|
||||||
prerr_string arg;
|
|
||||||
prerr_string "\""
|
|
||||||
end;
|
|
||||||
prerr_string ": ";
|
|
||||||
prerr_endline (error_message err);
|
|
||||||
exit 2
|
|
||||||
|
|
||||||
external environment : unit -> string array = "unix_environment"
|
|
||||||
external getenv: string -> string = "caml_sys_getenv"
|
|
||||||
external putenv: string -> string -> unit = "unix_putenv"
|
|
||||||
|
|
||||||
type process_status =
|
|
||||||
WEXITED of int
|
|
||||||
| WSIGNALED of int
|
|
||||||
| WSTOPPED of int
|
|
||||||
|
|
||||||
type wait_flag =
|
|
||||||
WNOHANG
|
|
||||||
| WUNTRACED
|
|
||||||
|
|
||||||
external execv : string -> string array -> 'a = "unix_execv"
|
|
||||||
external execve : string -> string array -> string array -> 'a = "unix_execve"
|
|
||||||
external execvp : string -> string array -> 'a = "unix_execvp"
|
|
||||||
external execvpe : string -> string array -> string array -> 'a = "unix_execvpe"
|
|
||||||
external fork : unit -> int = "unix_fork"
|
|
||||||
external wait : unit -> int * process_status = "unix_wait"
|
|
||||||
external waitpid : wait_flag list -> int -> int * process_status
|
|
||||||
= "unix_waitpid"
|
|
||||||
external getpid : unit -> int = "unix_getpid"
|
|
||||||
external getppid : unit -> int = "unix_getppid"
|
|
||||||
external nice : int -> int = "unix_nice"
|
|
||||||
|
|
||||||
type file_descr = int
|
|
||||||
|
|
||||||
let stdin = 0
|
|
||||||
let stdout = 1
|
|
||||||
let stderr = 2
|
|
||||||
|
|
||||||
type open_flag =
|
|
||||||
O_RDONLY
|
|
||||||
| O_WRONLY
|
|
||||||
| O_RDWR
|
|
||||||
| O_NONBLOCK
|
|
||||||
| O_APPEND
|
|
||||||
| O_CREAT
|
|
||||||
| O_TRUNC
|
|
||||||
| O_EXCL
|
|
||||||
| O_NOCTTY
|
|
||||||
| O_DSYNC
|
|
||||||
| O_SYNC
|
|
||||||
| O_RSYNC
|
|
||||||
| O_SHARE_DELETE
|
|
||||||
| O_CLOEXEC
|
|
||||||
|
|
||||||
type file_perm = int
|
|
||||||
|
|
||||||
|
|
||||||
external openfile : string -> open_flag list -> file_perm -> file_descr
|
|
||||||
= "unix_open"
|
|
||||||
|
|
||||||
external close : file_descr -> unit = "unix_close"
|
|
||||||
external unsafe_read : file_descr -> string -> int -> int -> int = "unix_read"
|
|
||||||
external unsafe_write : file_descr -> string -> int -> int -> int = "unix_write"
|
|
||||||
external unsafe_single_write : file_descr -> string -> int -> int -> int
|
|
||||||
= "unix_single_write"
|
|
||||||
|
|
||||||
let read fd buf ofs len =
|
|
||||||
if ofs < 0 || len < 0 || ofs > String.length buf - len
|
|
||||||
then invalid_arg "Unix.read"
|
|
||||||
else unsafe_read fd buf ofs len
|
|
||||||
let write fd buf ofs len =
|
|
||||||
if ofs < 0 || len < 0 || ofs > String.length buf - len
|
|
||||||
then invalid_arg "Unix.write"
|
|
||||||
else unsafe_write fd buf ofs len
|
|
||||||
(* write misbehaves because it attempts to write all data by making repeated
|
|
||||||
calls to the Unix write function (see comment in write.c and unix.mli).
|
|
||||||
partial_write fixes this by never calling write twice. *)
|
|
||||||
let single_write fd buf ofs len =
|
|
||||||
if ofs < 0 || len < 0 || ofs > String.length buf - len
|
|
||||||
then invalid_arg "Unix.single_write"
|
|
||||||
else unsafe_single_write fd buf ofs len
|
|
||||||
|
|
||||||
external in_channel_of_descr : file_descr -> in_channel
|
|
||||||
= "caml_ml_open_descriptor_in"
|
|
||||||
external out_channel_of_descr : file_descr -> out_channel
|
|
||||||
= "caml_ml_open_descriptor_out"
|
|
||||||
external descr_of_in_channel : in_channel -> file_descr
|
|
||||||
= "caml_channel_descriptor"
|
|
||||||
external descr_of_out_channel : out_channel -> file_descr
|
|
||||||
= "caml_channel_descriptor"
|
|
||||||
|
|
||||||
type seek_command =
|
|
||||||
SEEK_SET
|
|
||||||
| SEEK_CUR
|
|
||||||
| SEEK_END
|
|
||||||
|
|
||||||
external lseek : file_descr -> int -> seek_command -> int = "unix_lseek"
|
|
||||||
external truncate : string -> int -> unit = "unix_truncate"
|
|
||||||
external ftruncate : file_descr -> int -> unit = "unix_ftruncate"
|
|
||||||
|
|
||||||
type file_kind =
|
|
||||||
S_REG
|
|
||||||
| S_DIR
|
|
||||||
| S_CHR
|
|
||||||
| S_BLK
|
|
||||||
| S_LNK
|
|
||||||
| S_FIFO
|
|
||||||
| S_SOCK
|
|
||||||
|
|
||||||
type stats =
|
|
||||||
{ st_dev : int;
|
|
||||||
st_ino : int;
|
|
||||||
st_kind : file_kind;
|
|
||||||
st_perm : file_perm;
|
|
||||||
st_nlink : int;
|
|
||||||
st_uid : int;
|
|
||||||
st_gid : int;
|
|
||||||
st_rdev : int;
|
|
||||||
st_size : int;
|
|
||||||
st_atime : float;
|
|
||||||
st_mtime : float;
|
|
||||||
st_ctime : float }
|
|
||||||
|
|
||||||
external stat : string -> stats = "unix_stat"
|
|
||||||
external lstat : string -> stats = "unix_lstat"
|
|
||||||
external fstat : file_descr -> stats = "unix_fstat"
|
|
||||||
external isatty : file_descr -> bool = "unix_isatty"
|
|
||||||
external unlink : string -> unit = "unix_unlink"
|
|
||||||
external rename : string -> string -> unit = "unix_rename"
|
|
||||||
external link : string -> string -> unit = "unix_link"
|
|
||||||
|
|
||||||
module LargeFile =
|
|
||||||
struct
|
|
||||||
external lseek : file_descr -> int64 -> seek_command -> int64
|
|
||||||
= "unix_lseek_64"
|
|
||||||
external truncate : string -> int64 -> unit = "unix_truncate_64"
|
|
||||||
external ftruncate : file_descr -> int64 -> unit = "unix_ftruncate_64"
|
|
||||||
type stats =
|
|
||||||
{ st_dev : int;
|
|
||||||
st_ino : int;
|
|
||||||
st_kind : file_kind;
|
|
||||||
st_perm : file_perm;
|
|
||||||
st_nlink : int;
|
|
||||||
st_uid : int;
|
|
||||||
st_gid : int;
|
|
||||||
st_rdev : int;
|
|
||||||
st_size : int64;
|
|
||||||
st_atime : float;
|
|
||||||
st_mtime : float;
|
|
||||||
st_ctime : float;
|
|
||||||
}
|
|
||||||
external stat : string -> stats = "unix_stat_64"
|
|
||||||
external lstat : string -> stats = "unix_lstat_64"
|
|
||||||
external fstat : file_descr -> stats = "unix_fstat_64"
|
|
||||||
end
|
|
||||||
|
|
||||||
type access_permission =
|
|
||||||
R_OK
|
|
||||||
| W_OK
|
|
||||||
| X_OK
|
|
||||||
| F_OK
|
|
||||||
|
|
||||||
external chmod : string -> file_perm -> unit = "unix_chmod"
|
|
||||||
external fchmod : file_descr -> file_perm -> unit = "unix_fchmod"
|
|
||||||
external chown : string -> int -> int -> unit = "unix_chown"
|
|
||||||
external fchown : file_descr -> int -> int -> unit = "unix_fchown"
|
|
||||||
external umask : int -> int = "unix_umask"
|
|
||||||
external access : string -> access_permission list -> unit = "unix_access"
|
|
||||||
|
|
||||||
external dup : file_descr -> file_descr = "unix_dup"
|
|
||||||
external dup2 : file_descr -> file_descr -> unit = "unix_dup2"
|
|
||||||
external set_nonblock : file_descr -> unit = "unix_set_nonblock"
|
|
||||||
external clear_nonblock : file_descr -> unit = "unix_clear_nonblock"
|
|
||||||
external set_close_on_exec : file_descr -> unit = "unix_set_close_on_exec"
|
|
||||||
external clear_close_on_exec : file_descr -> unit = "unix_clear_close_on_exec"
|
|
||||||
|
|
||||||
(* FD_CLOEXEC should be supported on all Unix systems these days,
|
|
||||||
but just in case... *)
|
|
||||||
let try_set_close_on_exec fd =
|
|
||||||
try set_close_on_exec fd; true with Invalid_argument _ -> false
|
|
||||||
|
|
||||||
external mkdir : string -> file_perm -> unit = "unix_mkdir"
|
|
||||||
external rmdir : string -> unit = "unix_rmdir"
|
|
||||||
external chdir : string -> unit = "unix_chdir"
|
|
||||||
external getcwd : unit -> string = "unix_getcwd"
|
|
||||||
external chroot : string -> unit = "unix_chroot"
|
|
||||||
|
|
||||||
type dir_handle
|
|
||||||
|
|
||||||
external opendir : string -> dir_handle = "unix_opendir"
|
|
||||||
external readdir : dir_handle -> string = "unix_readdir"
|
|
||||||
external rewinddir : dir_handle -> unit = "unix_rewinddir"
|
|
||||||
external closedir : dir_handle -> unit = "unix_closedir"
|
|
||||||
|
|
||||||
external pipe : unit -> file_descr * file_descr = "unix_pipe"
|
|
||||||
external symlink : string -> string -> unit = "unix_symlink"
|
|
||||||
external readlink : string -> string = "unix_readlink"
|
|
||||||
external mkfifo : string -> file_perm -> unit = "unix_mkfifo"
|
|
||||||
external select :
|
|
||||||
file_descr list -> file_descr list -> file_descr list -> float ->
|
|
||||||
file_descr list * file_descr list * file_descr list = "unix_select"
|
|
||||||
|
|
||||||
type lock_command =
|
|
||||||
F_ULOCK
|
|
||||||
| F_LOCK
|
|
||||||
| F_TLOCK
|
|
||||||
| F_TEST
|
|
||||||
| F_RLOCK
|
|
||||||
| F_TRLOCK
|
|
||||||
|
|
||||||
external lockf : file_descr -> lock_command -> int -> unit = "unix_lockf"
|
|
||||||
external kill : int -> int -> unit = "unix_kill"
|
|
||||||
type sigprocmask_command = SIG_SETMASK | SIG_BLOCK | SIG_UNBLOCK
|
|
||||||
external sigprocmask: sigprocmask_command -> int list -> int list
|
|
||||||
= "unix_sigprocmask"
|
|
||||||
external sigpending: unit -> int list = "unix_sigpending"
|
|
||||||
external sigsuspend: int list -> unit = "unix_sigsuspend"
|
|
||||||
|
|
||||||
let pause() =
|
|
||||||
let sigs = sigprocmask SIG_BLOCK [] in sigsuspend sigs
|
|
||||||
|
|
||||||
type process_times =
|
|
||||||
{ tms_utime : float;
|
|
||||||
tms_stime : float;
|
|
||||||
tms_cutime : float;
|
|
||||||
tms_cstime : float }
|
|
||||||
|
|
||||||
type tm =
|
type tm =
|
||||||
{ tm_sec : int;
|
{ tm_sec : int;
|
||||||
tm_min : int;
|
tm_min : int;
|
||||||
|
@ -414,661 +98,6 @@ type tm =
|
||||||
tm_yday : int;
|
tm_yday : int;
|
||||||
tm_isdst : bool }
|
tm_isdst : bool }
|
||||||
|
|
||||||
external time : unit -> float = "unix_time"
|
|
||||||
external gettimeofday : unit -> float = "unix_gettimeofday"
|
external gettimeofday : unit -> float = "unix_gettimeofday"
|
||||||
external gmtime : float -> tm = "unix_gmtime"
|
|
||||||
external localtime : float -> tm = "unix_localtime"
|
external localtime : float -> tm = "unix_localtime"
|
||||||
external mktime : tm -> float * tm = "unix_mktime"
|
|
||||||
external alarm : int -> int = "unix_alarm"
|
|
||||||
external sleep : int -> unit = "unix_sleep"
|
|
||||||
external times : unit -> process_times = "unix_times"
|
|
||||||
external utimes : string -> float -> float -> unit = "unix_utimes"
|
|
||||||
|
|
||||||
type interval_timer =
|
|
||||||
ITIMER_REAL
|
|
||||||
| ITIMER_VIRTUAL
|
|
||||||
| ITIMER_PROF
|
|
||||||
|
|
||||||
type interval_timer_status =
|
|
||||||
{ it_interval: float; (* Period *)
|
|
||||||
it_value: float } (* Current value of the timer *)
|
|
||||||
|
|
||||||
external getitimer: interval_timer -> interval_timer_status = "unix_getitimer"
|
|
||||||
external setitimer:
|
|
||||||
interval_timer -> interval_timer_status -> interval_timer_status
|
|
||||||
= "unix_setitimer"
|
|
||||||
|
|
||||||
external getuid : unit -> int = "unix_getuid"
|
|
||||||
external geteuid : unit -> int = "unix_geteuid"
|
|
||||||
external setuid : int -> unit = "unix_setuid"
|
|
||||||
external getgid : unit -> int = "unix_getgid"
|
|
||||||
external getegid : unit -> int = "unix_getegid"
|
|
||||||
external setgid : int -> unit = "unix_setgid"
|
|
||||||
external getgroups : unit -> int array = "unix_getgroups"
|
|
||||||
external setgroups : int array -> unit = "unix_setgroups"
|
|
||||||
external initgroups : string -> int -> unit = "unix_initgroups"
|
|
||||||
|
|
||||||
type passwd_entry =
|
|
||||||
{ pw_name : string;
|
|
||||||
pw_passwd : string;
|
|
||||||
pw_uid : int;
|
|
||||||
pw_gid : int;
|
|
||||||
pw_gecos : string;
|
|
||||||
pw_dir : string;
|
|
||||||
pw_shell : string }
|
|
||||||
|
|
||||||
type group_entry =
|
|
||||||
{ gr_name : string;
|
|
||||||
gr_passwd : string;
|
|
||||||
gr_gid : int;
|
|
||||||
gr_mem : string array }
|
|
||||||
|
|
||||||
|
|
||||||
external getlogin : unit -> string = "unix_getlogin"
|
|
||||||
external getpwnam : string -> passwd_entry = "unix_getpwnam"
|
|
||||||
external getgrnam : string -> group_entry = "unix_getgrnam"
|
|
||||||
external getpwuid : int -> passwd_entry = "unix_getpwuid"
|
|
||||||
external getgrgid : int -> group_entry = "unix_getgrgid"
|
|
||||||
|
|
||||||
type inet_addr = string
|
|
||||||
|
|
||||||
let is_inet6_addr s = String.length s = 16
|
|
||||||
|
|
||||||
external inet_addr_of_string : string -> inet_addr
|
|
||||||
= "unix_inet_addr_of_string"
|
|
||||||
external string_of_inet_addr : inet_addr -> string
|
|
||||||
= "unix_string_of_inet_addr"
|
|
||||||
|
|
||||||
let inet_addr_any = inet_addr_of_string "0.0.0.0"
|
|
||||||
let inet_addr_loopback = inet_addr_of_string "127.0.0.1"
|
|
||||||
let inet6_addr_any =
|
|
||||||
try inet_addr_of_string "::" with Failure _ -> inet_addr_any
|
|
||||||
let inet6_addr_loopback =
|
|
||||||
try inet_addr_of_string "::1" with Failure _ -> inet_addr_loopback
|
|
||||||
|
|
||||||
type socket_domain =
|
|
||||||
PF_UNIX
|
|
||||||
| PF_INET
|
|
||||||
| PF_INET6
|
|
||||||
|
|
||||||
type socket_type =
|
|
||||||
SOCK_STREAM
|
|
||||||
| SOCK_DGRAM
|
|
||||||
| SOCK_RAW
|
|
||||||
| SOCK_SEQPACKET
|
|
||||||
|
|
||||||
type sockaddr =
|
|
||||||
ADDR_UNIX of string
|
|
||||||
| ADDR_INET of inet_addr * int
|
|
||||||
|
|
||||||
let domain_of_sockaddr = function
|
|
||||||
ADDR_UNIX _ -> PF_UNIX
|
|
||||||
| ADDR_INET(a, _) -> if is_inet6_addr a then PF_INET6 else PF_INET
|
|
||||||
|
|
||||||
type shutdown_command =
|
|
||||||
SHUTDOWN_RECEIVE
|
|
||||||
| SHUTDOWN_SEND
|
|
||||||
| SHUTDOWN_ALL
|
|
||||||
|
|
||||||
type msg_flag =
|
|
||||||
MSG_OOB
|
|
||||||
| MSG_DONTROUTE
|
|
||||||
| MSG_PEEK
|
|
||||||
|
|
||||||
external socket : socket_domain -> socket_type -> int -> file_descr
|
|
||||||
= "unix_socket"
|
|
||||||
external socketpair :
|
|
||||||
socket_domain -> socket_type -> int -> file_descr * file_descr
|
|
||||||
= "unix_socketpair"
|
|
||||||
external accept : file_descr -> file_descr * sockaddr = "unix_accept"
|
|
||||||
external bind : file_descr -> sockaddr -> unit = "unix_bind"
|
|
||||||
external connect : file_descr -> sockaddr -> unit = "unix_connect"
|
|
||||||
external listen : file_descr -> int -> unit = "unix_listen"
|
|
||||||
external shutdown : file_descr -> shutdown_command -> unit = "unix_shutdown"
|
|
||||||
external getsockname : file_descr -> sockaddr = "unix_getsockname"
|
|
||||||
external getpeername : file_descr -> sockaddr = "unix_getpeername"
|
|
||||||
|
|
||||||
external unsafe_recv :
|
|
||||||
file_descr -> string -> int -> int -> msg_flag list -> int
|
|
||||||
= "unix_recv"
|
|
||||||
external unsafe_recvfrom :
|
|
||||||
file_descr -> string -> int -> int -> msg_flag list -> int * sockaddr
|
|
||||||
= "unix_recvfrom"
|
|
||||||
external unsafe_send :
|
|
||||||
file_descr -> string -> int -> int -> msg_flag list -> int
|
|
||||||
= "unix_send"
|
|
||||||
external unsafe_sendto :
|
|
||||||
file_descr -> string -> int -> int -> msg_flag list -> sockaddr -> int
|
|
||||||
= "unix_sendto" "unix_sendto_native"
|
|
||||||
|
|
||||||
let recv fd buf ofs len flags =
|
|
||||||
if ofs < 0 || len < 0 || ofs > String.length buf - len
|
|
||||||
then invalid_arg "Unix.recv"
|
|
||||||
else unsafe_recv fd buf ofs len flags
|
|
||||||
let recvfrom fd buf ofs len flags =
|
|
||||||
if ofs < 0 || len < 0 || ofs > String.length buf - len
|
|
||||||
then invalid_arg "Unix.recvfrom"
|
|
||||||
else unsafe_recvfrom fd buf ofs len flags
|
|
||||||
let send fd buf ofs len flags =
|
|
||||||
if ofs < 0 || len < 0 || ofs > String.length buf - len
|
|
||||||
then invalid_arg "Unix.send"
|
|
||||||
else unsafe_send fd buf ofs len flags
|
|
||||||
let sendto fd buf ofs len flags addr =
|
|
||||||
if ofs < 0 || len < 0 || ofs > String.length buf - len
|
|
||||||
then invalid_arg "Unix.sendto"
|
|
||||||
else unsafe_sendto fd buf ofs len flags addr
|
|
||||||
|
|
||||||
type socket_bool_option =
|
|
||||||
SO_DEBUG
|
|
||||||
| SO_BROADCAST
|
|
||||||
| SO_REUSEADDR
|
|
||||||
| SO_KEEPALIVE
|
|
||||||
| SO_DONTROUTE
|
|
||||||
| SO_OOBINLINE
|
|
||||||
| SO_ACCEPTCONN
|
|
||||||
| TCP_NODELAY
|
|
||||||
| IPV6_ONLY
|
|
||||||
|
|
||||||
type socket_int_option =
|
|
||||||
SO_SNDBUF
|
|
||||||
| SO_RCVBUF
|
|
||||||
| SO_ERROR
|
|
||||||
| SO_TYPE
|
|
||||||
| SO_RCVLOWAT
|
|
||||||
| SO_SNDLOWAT
|
|
||||||
|
|
||||||
type socket_optint_option = SO_LINGER
|
|
||||||
|
|
||||||
type socket_float_option =
|
|
||||||
SO_RCVTIMEO
|
|
||||||
| SO_SNDTIMEO
|
|
||||||
|
|
||||||
type socket_error_option = SO_ERROR
|
|
||||||
|
|
||||||
module SO: sig
|
|
||||||
type ('opt, 'v) t
|
|
||||||
val bool: (socket_bool_option, bool) t
|
|
||||||
val int: (socket_int_option, int) t
|
|
||||||
val optint: (socket_optint_option, int option) t
|
|
||||||
val float: (socket_float_option, float) t
|
|
||||||
val error: (socket_error_option, error option) t
|
|
||||||
val get: ('opt, 'v) t -> file_descr -> 'opt -> 'v
|
|
||||||
val set: ('opt, 'v) t -> file_descr -> 'opt -> 'v -> unit
|
|
||||||
end = struct
|
|
||||||
type ('opt, 'v) t = int
|
|
||||||
let bool = 0
|
|
||||||
let int = 1
|
|
||||||
let optint = 2
|
|
||||||
let float = 3
|
|
||||||
let error = 4
|
|
||||||
external get: ('opt, 'v) t -> file_descr -> 'opt -> 'v
|
|
||||||
= "unix_getsockopt"
|
|
||||||
external set: ('opt, 'v) t -> file_descr -> 'opt -> 'v -> unit
|
|
||||||
= "unix_setsockopt"
|
|
||||||
end
|
|
||||||
|
|
||||||
let getsockopt fd opt = SO.get SO.bool fd opt
|
|
||||||
let setsockopt fd opt v = SO.set SO.bool fd opt v
|
|
||||||
|
|
||||||
let getsockopt_int fd opt = SO.get SO.int fd opt
|
|
||||||
let setsockopt_int fd opt v = SO.set SO.int fd opt v
|
|
||||||
|
|
||||||
let getsockopt_optint fd opt = SO.get SO.optint fd opt
|
|
||||||
let setsockopt_optint fd opt v = SO.set SO.optint fd opt v
|
|
||||||
|
|
||||||
let getsockopt_float fd opt = SO.get SO.float fd opt
|
|
||||||
let setsockopt_float fd opt v = SO.set SO.float fd opt v
|
|
||||||
|
|
||||||
let getsockopt_error fd = SO.get SO.error fd SO_ERROR
|
|
||||||
|
|
||||||
type host_entry =
|
|
||||||
{ h_name : string;
|
|
||||||
h_aliases : string array;
|
|
||||||
h_addrtype : socket_domain;
|
|
||||||
h_addr_list : inet_addr array }
|
|
||||||
|
|
||||||
type protocol_entry =
|
|
||||||
{ p_name : string;
|
|
||||||
p_aliases : string array;
|
|
||||||
p_proto : int }
|
|
||||||
|
|
||||||
type service_entry =
|
|
||||||
{ s_name : string;
|
|
||||||
s_aliases : string array;
|
|
||||||
s_port : int;
|
|
||||||
s_proto : string }
|
|
||||||
|
|
||||||
external gethostname : unit -> string = "unix_gethostname"
|
|
||||||
external gethostbyname : string -> host_entry = "unix_gethostbyname"
|
|
||||||
external gethostbyaddr : inet_addr -> host_entry = "unix_gethostbyaddr"
|
|
||||||
external getprotobyname : string -> protocol_entry
|
|
||||||
= "unix_getprotobyname"
|
|
||||||
external getprotobynumber : int -> protocol_entry
|
|
||||||
= "unix_getprotobynumber"
|
|
||||||
external getservbyname : string -> string -> service_entry
|
|
||||||
= "unix_getservbyname"
|
|
||||||
external getservbyport : int -> string -> service_entry
|
|
||||||
= "unix_getservbyport"
|
|
||||||
|
|
||||||
type addr_info =
|
|
||||||
{ ai_family : socket_domain;
|
|
||||||
ai_socktype : socket_type;
|
|
||||||
ai_protocol : int;
|
|
||||||
ai_addr : sockaddr;
|
|
||||||
ai_canonname : string }
|
|
||||||
|
|
||||||
type getaddrinfo_option =
|
|
||||||
AI_FAMILY of socket_domain
|
|
||||||
| AI_SOCKTYPE of socket_type
|
|
||||||
| AI_PROTOCOL of int
|
|
||||||
| AI_NUMERICHOST
|
|
||||||
| AI_CANONNAME
|
|
||||||
| AI_PASSIVE
|
|
||||||
|
|
||||||
external getaddrinfo_system
|
|
||||||
: string -> string -> getaddrinfo_option list -> addr_info list
|
|
||||||
= "unix_getaddrinfo"
|
|
||||||
|
|
||||||
let getaddrinfo_emulation node service opts =
|
|
||||||
(* Parse options *)
|
|
||||||
let opt_socktype = ref None
|
|
||||||
and opt_protocol = ref 0
|
|
||||||
and opt_passive = ref false in
|
|
||||||
List.iter
|
|
||||||
(function AI_SOCKTYPE s -> opt_socktype := Some s
|
|
||||||
| AI_PROTOCOL p -> opt_protocol := p
|
|
||||||
| AI_PASSIVE -> opt_passive := true
|
|
||||||
| _ -> ())
|
|
||||||
opts;
|
|
||||||
(* Determine socket types and port numbers *)
|
|
||||||
let get_port ty kind =
|
|
||||||
if service = "" then [ty, 0] else
|
|
||||||
try
|
|
||||||
[ty, int_of_string service]
|
|
||||||
with Failure _ ->
|
|
||||||
try
|
|
||||||
[ty, (getservbyname service kind).s_port]
|
|
||||||
with Not_found -> []
|
|
||||||
in
|
|
||||||
let ports =
|
|
||||||
match !opt_socktype with
|
|
||||||
| None ->
|
|
||||||
get_port SOCK_STREAM "tcp" @ get_port SOCK_DGRAM "udp"
|
|
||||||
| Some SOCK_STREAM ->
|
|
||||||
get_port SOCK_STREAM "tcp"
|
|
||||||
| Some SOCK_DGRAM ->
|
|
||||||
get_port SOCK_DGRAM "udp"
|
|
||||||
| Some ty ->
|
|
||||||
if service = "" then [ty, 0] else [] in
|
|
||||||
(* Determine IP addresses *)
|
|
||||||
let addresses =
|
|
||||||
if node = "" then
|
|
||||||
if List.mem AI_PASSIVE opts
|
|
||||||
then [inet_addr_any, "0.0.0.0"]
|
|
||||||
else [inet_addr_loopback, "127.0.0.1"]
|
|
||||||
else
|
|
||||||
try
|
|
||||||
[inet_addr_of_string node, node]
|
|
||||||
with Failure _ ->
|
|
||||||
try
|
|
||||||
let he = gethostbyname node in
|
|
||||||
List.map
|
|
||||||
(fun a -> (a, he.h_name))
|
|
||||||
(Array.to_list he.h_addr_list)
|
|
||||||
with Not_found ->
|
|
||||||
[] in
|
|
||||||
(* Cross-product of addresses and ports *)
|
|
||||||
List.flatten
|
|
||||||
(List.map
|
|
||||||
(fun (ty, port) ->
|
|
||||||
List.map
|
|
||||||
(fun (addr, name) ->
|
|
||||||
{ ai_family = PF_INET;
|
|
||||||
ai_socktype = ty;
|
|
||||||
ai_protocol = !opt_protocol;
|
|
||||||
ai_addr = ADDR_INET(addr, port);
|
|
||||||
ai_canonname = name })
|
|
||||||
addresses)
|
|
||||||
ports)
|
|
||||||
|
|
||||||
let getaddrinfo node service opts =
|
|
||||||
try
|
|
||||||
List.rev(getaddrinfo_system node service opts)
|
|
||||||
with Invalid_argument _ ->
|
|
||||||
getaddrinfo_emulation node service opts
|
|
||||||
|
|
||||||
type name_info =
|
|
||||||
{ ni_hostname : string;
|
|
||||||
ni_service : string }
|
|
||||||
|
|
||||||
type getnameinfo_option =
|
|
||||||
NI_NOFQDN
|
|
||||||
| NI_NUMERICHOST
|
|
||||||
| NI_NAMEREQD
|
|
||||||
| NI_NUMERICSERV
|
|
||||||
| NI_DGRAM
|
|
||||||
|
|
||||||
external getnameinfo_system
|
|
||||||
: sockaddr -> getnameinfo_option list -> name_info
|
|
||||||
= "unix_getnameinfo"
|
|
||||||
|
|
||||||
let getnameinfo_emulation addr opts =
|
|
||||||
match addr with
|
|
||||||
| ADDR_UNIX f ->
|
|
||||||
{ ni_hostname = ""; ni_service = f } (* why not? *)
|
|
||||||
| ADDR_INET(a, p) ->
|
|
||||||
let hostname =
|
|
||||||
try
|
|
||||||
if List.mem NI_NUMERICHOST opts then raise Not_found;
|
|
||||||
(gethostbyaddr a).h_name
|
|
||||||
with Not_found ->
|
|
||||||
if List.mem NI_NAMEREQD opts then raise Not_found;
|
|
||||||
string_of_inet_addr a in
|
|
||||||
let service =
|
|
||||||
try
|
|
||||||
if List.mem NI_NUMERICSERV opts then raise Not_found;
|
|
||||||
let kind = if List.mem NI_DGRAM opts then "udp" else "tcp" in
|
|
||||||
(getservbyport p kind).s_name
|
|
||||||
with Not_found ->
|
|
||||||
string_of_int p in
|
|
||||||
{ ni_hostname = hostname; ni_service = service }
|
|
||||||
|
|
||||||
let getnameinfo addr opts =
|
|
||||||
try
|
|
||||||
getnameinfo_system addr opts
|
|
||||||
with Invalid_argument _ ->
|
|
||||||
getnameinfo_emulation addr opts
|
|
||||||
|
|
||||||
type terminal_io = {
|
|
||||||
mutable c_ignbrk: bool;
|
|
||||||
mutable c_brkint: bool;
|
|
||||||
mutable c_ignpar: bool;
|
|
||||||
mutable c_parmrk: bool;
|
|
||||||
mutable c_inpck: bool;
|
|
||||||
mutable c_istrip: bool;
|
|
||||||
mutable c_inlcr: bool;
|
|
||||||
mutable c_igncr: bool;
|
|
||||||
mutable c_icrnl: bool;
|
|
||||||
mutable c_ixon: bool;
|
|
||||||
mutable c_ixoff: bool;
|
|
||||||
mutable c_opost: bool;
|
|
||||||
mutable c_obaud: int;
|
|
||||||
mutable c_ibaud: int;
|
|
||||||
mutable c_csize: int;
|
|
||||||
mutable c_cstopb: int;
|
|
||||||
mutable c_cread: bool;
|
|
||||||
mutable c_parenb: bool;
|
|
||||||
mutable c_parodd: bool;
|
|
||||||
mutable c_hupcl: bool;
|
|
||||||
mutable c_clocal: bool;
|
|
||||||
mutable c_isig: bool;
|
|
||||||
mutable c_icanon: bool;
|
|
||||||
mutable c_noflsh: bool;
|
|
||||||
mutable c_echo: bool;
|
|
||||||
mutable c_echoe: bool;
|
|
||||||
mutable c_echok: bool;
|
|
||||||
mutable c_echonl: bool;
|
|
||||||
mutable c_vintr: char;
|
|
||||||
mutable c_vquit: char;
|
|
||||||
mutable c_verase: char;
|
|
||||||
mutable c_vkill: char;
|
|
||||||
mutable c_veof: char;
|
|
||||||
mutable c_veol: char;
|
|
||||||
mutable c_vmin: int;
|
|
||||||
mutable c_vtime: int;
|
|
||||||
mutable c_vstart: char;
|
|
||||||
mutable c_vstop: char
|
|
||||||
}
|
|
||||||
|
|
||||||
external tcgetattr: file_descr -> terminal_io = "unix_tcgetattr"
|
|
||||||
|
|
||||||
type setattr_when = TCSANOW | TCSADRAIN | TCSAFLUSH
|
|
||||||
|
|
||||||
external tcsetattr: file_descr -> setattr_when -> terminal_io -> unit
|
|
||||||
= "unix_tcsetattr"
|
|
||||||
external tcsendbreak: file_descr -> int -> unit = "unix_tcsendbreak"
|
|
||||||
external tcdrain: file_descr -> unit = "unix_tcdrain"
|
|
||||||
|
|
||||||
type flush_queue = TCIFLUSH | TCOFLUSH | TCIOFLUSH
|
|
||||||
|
|
||||||
external tcflush: file_descr -> flush_queue -> unit = "unix_tcflush"
|
|
||||||
|
|
||||||
type flow_action = TCOOFF | TCOON | TCIOFF | TCION
|
|
||||||
|
|
||||||
external tcflow: file_descr -> flow_action -> unit = "unix_tcflow"
|
|
||||||
|
|
||||||
external setsid : unit -> int = "unix_setsid"
|
|
||||||
|
|
||||||
(* High-level process management (system, popen) *)
|
|
||||||
|
|
||||||
let rec waitpid_non_intr pid =
|
|
||||||
try waitpid [] pid
|
|
||||||
with Unix_error (EINTR, _, _) -> waitpid_non_intr pid
|
|
||||||
|
|
||||||
let system cmd =
|
|
||||||
match fork() with
|
|
||||||
0 -> begin try
|
|
||||||
execv "/bin/sh" [| "/bin/sh"; "-c"; cmd |]
|
|
||||||
with _ ->
|
|
||||||
exit 127
|
|
||||||
end
|
|
||||||
| id -> snd(waitpid_non_intr id)
|
|
||||||
|
|
||||||
let rec safe_dup fd =
|
|
||||||
let new_fd = dup fd in
|
|
||||||
if new_fd >= 3 then
|
|
||||||
new_fd
|
|
||||||
else begin
|
|
||||||
let res = safe_dup fd in
|
|
||||||
close new_fd;
|
|
||||||
res
|
|
||||||
end
|
|
||||||
|
|
||||||
let safe_close fd =
|
|
||||||
try close fd with Unix_error(_,_,_) -> ()
|
|
||||||
|
|
||||||
let perform_redirections new_stdin new_stdout new_stderr =
|
|
||||||
let newnewstdin = safe_dup new_stdin in
|
|
||||||
let newnewstdout = safe_dup new_stdout in
|
|
||||||
let newnewstderr = safe_dup new_stderr in
|
|
||||||
safe_close new_stdin;
|
|
||||||
safe_close new_stdout;
|
|
||||||
safe_close new_stderr;
|
|
||||||
dup2 newnewstdin stdin; close newnewstdin;
|
|
||||||
dup2 newnewstdout stdout; close newnewstdout;
|
|
||||||
dup2 newnewstderr stderr; close newnewstderr
|
|
||||||
|
|
||||||
let create_process cmd args new_stdin new_stdout new_stderr =
|
|
||||||
match fork() with
|
|
||||||
0 ->
|
|
||||||
begin try
|
|
||||||
perform_redirections new_stdin new_stdout new_stderr;
|
|
||||||
execvp cmd args
|
|
||||||
with _ ->
|
|
||||||
exit 127
|
|
||||||
end
|
|
||||||
| id -> id
|
|
||||||
|
|
||||||
let create_process_env cmd args env new_stdin new_stdout new_stderr =
|
|
||||||
match fork() with
|
|
||||||
0 ->
|
|
||||||
begin try
|
|
||||||
perform_redirections new_stdin new_stdout new_stderr;
|
|
||||||
execvpe cmd args env
|
|
||||||
with _ ->
|
|
||||||
exit 127
|
|
||||||
end
|
|
||||||
| id -> id
|
|
||||||
|
|
||||||
type popen_process =
|
|
||||||
Process of in_channel * out_channel
|
|
||||||
| Process_in of in_channel
|
|
||||||
| Process_out of out_channel
|
|
||||||
| Process_full of in_channel * out_channel * in_channel
|
|
||||||
|
|
||||||
let popen_processes = (Hashtbl.create 7 : (popen_process, int) Hashtbl.t)
|
|
||||||
|
|
||||||
let open_proc cmd proc input output toclose =
|
|
||||||
let cloexec = List.for_all try_set_close_on_exec toclose in
|
|
||||||
match fork() with
|
|
||||||
0 -> if input <> stdin then begin dup2 input stdin; close input end;
|
|
||||||
if output <> stdout then begin dup2 output stdout; close output end;
|
|
||||||
if not cloexec then List.iter close toclose;
|
|
||||||
begin try execv "/bin/sh" [| "/bin/sh"; "-c"; cmd |]
|
|
||||||
with _ -> exit 127
|
|
||||||
end
|
|
||||||
| id -> Hashtbl.add popen_processes proc id
|
|
||||||
|
|
||||||
let open_process_in cmd =
|
|
||||||
let (in_read, in_write) = pipe() in
|
|
||||||
let inchan = in_channel_of_descr in_read in
|
|
||||||
begin
|
|
||||||
try
|
|
||||||
open_proc cmd (Process_in inchan) stdin in_write [in_read];
|
|
||||||
with e ->
|
|
||||||
close_in inchan;
|
|
||||||
close in_write;
|
|
||||||
raise e
|
|
||||||
end;
|
|
||||||
close in_write;
|
|
||||||
inchan
|
|
||||||
|
|
||||||
let open_process_out cmd =
|
|
||||||
let (out_read, out_write) = pipe() in
|
|
||||||
let outchan = out_channel_of_descr out_write in
|
|
||||||
begin
|
|
||||||
try
|
|
||||||
open_proc cmd (Process_out outchan) out_read stdout [out_write];
|
|
||||||
with e ->
|
|
||||||
close_out outchan;
|
|
||||||
close out_read;
|
|
||||||
raise e
|
|
||||||
end;
|
|
||||||
close out_read;
|
|
||||||
outchan
|
|
||||||
|
|
||||||
let open_process cmd =
|
|
||||||
let (in_read, in_write) = pipe() in
|
|
||||||
let fds_to_close = ref [in_read;in_write] in
|
|
||||||
try
|
|
||||||
let (out_read, out_write) = pipe() in
|
|
||||||
fds_to_close := [in_read;in_write;out_read;out_write];
|
|
||||||
let inchan = in_channel_of_descr in_read in
|
|
||||||
let outchan = out_channel_of_descr out_write in
|
|
||||||
open_proc cmd (Process(inchan, outchan)) out_read in_write
|
|
||||||
[in_read; out_write];
|
|
||||||
close out_read;
|
|
||||||
close in_write;
|
|
||||||
(inchan, outchan)
|
|
||||||
with e ->
|
|
||||||
List.iter close !fds_to_close;
|
|
||||||
raise e
|
|
||||||
|
|
||||||
let open_proc_full cmd env proc input output error toclose =
|
|
||||||
let cloexec = List.for_all try_set_close_on_exec toclose in
|
|
||||||
match fork() with
|
|
||||||
0 -> dup2 input stdin; close input;
|
|
||||||
dup2 output stdout; close output;
|
|
||||||
dup2 error stderr; close error;
|
|
||||||
if not cloexec then List.iter close toclose;
|
|
||||||
begin try execve "/bin/sh" [| "/bin/sh"; "-c"; cmd |] env
|
|
||||||
with _ -> exit 127
|
|
||||||
end
|
|
||||||
| id -> Hashtbl.add popen_processes proc id
|
|
||||||
|
|
||||||
let open_process_full cmd env =
|
|
||||||
let (in_read, in_write) = pipe() in
|
|
||||||
let fds_to_close = ref [in_read;in_write] in
|
|
||||||
try
|
|
||||||
let (out_read, out_write) = pipe() in
|
|
||||||
fds_to_close := out_read::out_write:: !fds_to_close;
|
|
||||||
let (err_read, err_write) = pipe() in
|
|
||||||
fds_to_close := err_read::err_write:: !fds_to_close;
|
|
||||||
let inchan = in_channel_of_descr in_read in
|
|
||||||
let outchan = out_channel_of_descr out_write in
|
|
||||||
let errchan = in_channel_of_descr err_read in
|
|
||||||
open_proc_full cmd env (Process_full(inchan, outchan, errchan))
|
|
||||||
out_read in_write err_write [in_read; out_write; err_read];
|
|
||||||
close out_read;
|
|
||||||
close in_write;
|
|
||||||
close err_write;
|
|
||||||
(inchan, outchan, errchan)
|
|
||||||
with e ->
|
|
||||||
List.iter close !fds_to_close;
|
|
||||||
raise e
|
|
||||||
|
|
||||||
let find_proc_id fun_name proc =
|
|
||||||
try
|
|
||||||
let pid = Hashtbl.find popen_processes proc in
|
|
||||||
Hashtbl.remove popen_processes proc;
|
|
||||||
pid
|
|
||||||
with Not_found ->
|
|
||||||
raise(Unix_error(EBADF, fun_name, ""))
|
|
||||||
|
|
||||||
let close_process_in inchan =
|
|
||||||
let pid = find_proc_id "close_process_in" (Process_in inchan) in
|
|
||||||
close_in inchan;
|
|
||||||
snd(waitpid_non_intr pid)
|
|
||||||
|
|
||||||
let close_process_out outchan =
|
|
||||||
let pid = find_proc_id "close_process_out" (Process_out outchan) in
|
|
||||||
close_out outchan;
|
|
||||||
snd(waitpid_non_intr pid)
|
|
||||||
|
|
||||||
let close_process (inchan, outchan) =
|
|
||||||
let pid = find_proc_id "close_process" (Process(inchan, outchan)) in
|
|
||||||
close_in inchan;
|
|
||||||
begin try close_out outchan with Sys_error _ -> () end;
|
|
||||||
snd(waitpid_non_intr pid)
|
|
||||||
|
|
||||||
let close_process_full (inchan, outchan, errchan) =
|
|
||||||
let pid =
|
|
||||||
find_proc_id "close_process_full"
|
|
||||||
(Process_full(inchan, outchan, errchan)) in
|
|
||||||
close_in inchan;
|
|
||||||
begin try close_out outchan with Sys_error _ -> () end;
|
|
||||||
close_in errchan;
|
|
||||||
snd(waitpid_non_intr pid)
|
|
||||||
|
|
||||||
(* High-level network functions *)
|
|
||||||
|
|
||||||
let open_connection sockaddr =
|
|
||||||
let sock =
|
|
||||||
socket (domain_of_sockaddr sockaddr) SOCK_STREAM 0 in
|
|
||||||
try
|
|
||||||
connect sock sockaddr;
|
|
||||||
ignore(try_set_close_on_exec sock);
|
|
||||||
(in_channel_of_descr sock, out_channel_of_descr sock)
|
|
||||||
with exn ->
|
|
||||||
close sock; raise exn
|
|
||||||
|
|
||||||
let shutdown_connection inchan =
|
|
||||||
shutdown (descr_of_in_channel inchan) SHUTDOWN_SEND
|
|
||||||
|
|
||||||
let rec accept_non_intr s =
|
|
||||||
try accept s
|
|
||||||
with Unix_error (EINTR, _, _) -> accept_non_intr s
|
|
||||||
|
|
||||||
let establish_server server_fun sockaddr =
|
|
||||||
let sock =
|
|
||||||
socket (domain_of_sockaddr sockaddr) SOCK_STREAM 0 in
|
|
||||||
setsockopt sock SO_REUSEADDR true;
|
|
||||||
bind sock sockaddr;
|
|
||||||
listen sock 5;
|
|
||||||
while true do
|
|
||||||
let (s, caller) = accept_non_intr sock in
|
|
||||||
(* The "double fork" trick, the process which calls server_fun will not
|
|
||||||
leave a zombie process *)
|
|
||||||
match fork() with
|
|
||||||
0 -> if fork() <> 0 then exit 0; (* The son exits, the grandson works *)
|
|
||||||
close sock;
|
|
||||||
ignore(try_set_close_on_exec s);
|
|
||||||
let inchan = in_channel_of_descr s in
|
|
||||||
let outchan = out_channel_of_descr s in
|
|
||||||
server_fun inchan outchan;
|
|
||||||
(* Do not close inchan nor outchan, as the server_fun could
|
|
||||||
have done it already, and we are about to exit anyway
|
|
||||||
(PR#3794) *)
|
|
||||||
exit 0
|
|
||||||
| id -> close s; ignore(waitpid_non_intr id) (* Reclaim the son *)
|
|
||||||
done
|
|
||||||
|
|
1311
cpdfunix.mli
1311
cpdfunix.mli
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue