diff options
-rw-r--r-- | pflocal/connq.h | 294 | ||||
-rw-r--r-- | pflocal/sock.h | 294 |
2 files changed, 588 insertions, 0 deletions
diff --git a/pflocal/connq.h b/pflocal/connq.h new file mode 100644 index 00000000..a858d019 --- /dev/null +++ b/pflocal/connq.h @@ -0,0 +1,294 @@ +/* A server for local sockets, of type PF_LOCAL + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by Miles Bader <miles@gnu.ai.mit.edu> + + 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, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef __PFLOCAL_H__ +#define __PFLOCAL_H__ + +/* ---------------------------------------------------------------- */ +/* Sockets */ + +/* A port on SOCK. Multiple sock_user's can point to the same socket. */ +struct sock_user +{ + struct port_info pi; + struct sock *sock; +}; + +/* An endpoint for a possible I/O stream. */ +struct sock +{ + int refs; + struct mutex lock; + + /* Reads from this socket come from READ_PIPE, writes go to WRITE_PIPE. + A sock always has a read pipe, and a write pipe when it's connected to + another socket. */ + struct pipe *read_pipe, *write_pipe; + + /* FLAGS from SOCK_*, below. */ + unsigned flags; + + /* An identifying number for the socket. */ + unsigned id; + /* Last time the socket got frobbed. */ + time_value_t change_time; + + /* This socket's local address. Note that we don't hold any references on + ADDR, and depend on the addr zeroing our pointer if it goes away (which + is ok, as we can then just make up another address if necessary, and no + one could tell anyway). */ + struct addr *addr; + + /* If this sock has been connected to another sock, then WRITE_ADDR is the + addr of that sock. We *do* hold a reference to this addr. */ + struct addr *write_addr; + + /* A connection queue to listen for incoming connections on. Once a socket + has one of these, it always does, and can never again be used for + anything but accepting incoming connections. */ + struct connq *connq; +}; + +/* Socket flags */ +#define SOCK_CONNECTED 0x1 /* A connected connection-oriented sock. */ +#define SOCK_NONBLOCK 0x2 /* Don't block on I/O. */ +#define SOCK_SHUTDOWN_READ 0x4 /* The read-half has been shutdown. */ +#define SOCK_SHUTDOWN_WRITE 0x8 /* The write-half has been shutdown. */ + +/* Returns the pipe that SOCK is reading from in PIPE, locked and with an + additional reference, or an error saying why it's not possible. NULL may + also be returned in PIPE with a 0 error, meaning that EOF should be + returned. SOCK mustn't be locked. */ +error_t sock_aquire_read_pipe (struct sock *sock, struct pipe **pipe); + +/* Returns the pipe that SOCK is writing to in PIPE, locked and with an + additional reference, or an error saying why it's not possible. SOCK + mustn't be locked. */ +error_t sock_aquire_write_pipe (struct sock *sock, struct pipe **pipe); + +/* Connect together the previously unconnected sockets SOCK1 and SOCK2. */ +error_t sock_connect (struct sock *sock1, struct sock *sock2) + +/* Return a new socket with the given pipe class in SOCK. */ +error_t sock_create (struct pipe_class *pipe_class, struct sock **sock); + +/* Return a new socket just like TEMPLATE in SOCK. */ +error_t sock_create (struct sock *template, struct sock **sock); + +/* Return a new user port on SOCK in PORT. */ +error_t sock_create_port (struct sock *sock, mach_port_t *port); + +/* ---------------------------------------------------------------- */ +/* Pipes */ + +/* A description of a class of pipes and how to operate on them. */ +struct pipe_class +{ + /* What sort of socket this corresponds too. */ + int sock_type; + + /* Flags, from PIPE_CLASS_*, below. */ + unsigned flags; + + /* Operations: */ + + /* Read from BUF into DATA &c. */ + error_t (*read)(void *buf, char **data, unsigned *data_len, unsigned amount); + /* Write DATA &c into BUF. */ + error_t (*write)(void *buf, char *data, unsigned data_len, unsigned *amount); + /* Return the number of readable characters in BUF. */ + unsigned (*readable)(void *buf); + /* Clear out any data. */ + error_t (*drain)(void *buf); + /* Initialize *BUF or return an error. */ + error_t (*init)(void **buf); + /* Cleanup BUF, freeing all resources. */ + void (*cleanup)(void *buf); +}; + +/* pipe_class flags */ +#define PIPE_CLASS_CONNECTIONLESS 0x1 /* A non-stream protocol. */ + +/* Some pre-defined pipe_classes. */ +struct pipe_class *stream_pipe_class; +struct pipe_class *dgram_pipe_class; +struct pipe_class *seqpacket_pipe_class; + +/* ---------------------------------------------------------------- */ + +/* A unidirectional data pipe; it transfers data from READER to WRITER. */ +struct pipe +{ + /* What kind of pipe we are. */ + struct pipe_class *class; + + /* We use this to keep track of active threads using this pipe, so that + while a thread is waiting to read from a pipe and that pipe gets + deallocated (say by socket_shutdown), it doesn't actually go away until + the reader realizes what happened. It is normally frobbed using + pipe_aquire & pipe_release, which do locking as well.. */ + unsigned refs; + + /* Various flags, from PIPE_* below. */ + unsigned flags; + + /* Various timestamps for this pipe. */ + time_value_t read_time; + time_value_t write_time; + + struct condition pending_reads; + struct condition pending_selects; + + struct mutex lock; + + /* When interrupt_operation is called on a socket, we want to wake up all + pending read threads, and have them realize they've been interrupted; + reads that happen after the interrupt shouldn't return EINTR. When a + thread waits on this pipe's PENDING_READS condition, it remembers this + sequence number; any interrupt bumps this number and broadcasts on the + condition. A reader thread will try to read from the pipe only if the + sequence number is the same as when it went to sleep. */ + unsigned long interrupt_seq_num; + + /* The actual data, and how to access it. */ + void *data; +}; + +/* Pipe flags. */ +#define PIPE_BROKEN 0x1 /* This pipe isn't connected. */ + +/* Lock PIPE and increment its ref count. */ +extern inline void +pipe_aquire (struct pipe *pipe) +{ + mutex_lock (&pipe->lock); + pipe->refs++; +} + +/* Decrement PIPE's (which should be locked) ref count and unlock it. If the + ref count goes to zero, PIPE will be destroyed. */ +extern inline void +pipe_release (struct pipe *pipe) +{ + if (--pipe->refs == 0) + pipe_free (pipe); + else + mutex_unlock (&pipe->lock); +} + +/* Returns the number of characters quickly readable from PIPE. */ +extern inline unsigned +pipe_readable (struct pipe *pipe) +{ + return (*pipe->class->readable)(pipe->data); +} + +/* Empty out PIPE of any data. */ +extern inline void +pipe_drain (struct pipe *pipe) +{ + (*pipe->class->drain)(pipe->data); +} + +/* Writes up to LEN bytes of DATA, to PIPE, and returns the amount written in + AMOUNT. If an error is returned, nothing is done. */ +error_t +pipe_write (struct pipe *pipe, char *data, unsigned len, unsigned *amount); + +/* Reads up to AMOUNT bytes from PIPE, which should be locked, into DATA, and + returns the amount written in LEN. If NOBLOCK is true, EWOULDBLOCK is + returned instead of block when no data is immediately available. If an + error is returned, nothing is done. */ +error_t pipe_read (struct pipe *pipe, int noblock, + char **data, unsigned *len, unsigned amount); + +/* Waits for PIPE to be readable, or an error to occurr. If NOBLOCK is true, + this operation will return EWOULDBLOCK instead of blocking when no data is + immediately available. */ +error_t pipe_wait (struct pipe *pipe, int noblock); + +/* Wake up all threads waiting on PIPE, which should be locked. */ +void pipe_kick (struct pipe *pipe); + +/* Creates a new pipe of class CLASS and returns it in RESULT. */ +error_t pipe_create (struct pipe_class *class, struct pipe **pipe); + +/* Free PIPE and any resources it holds. */ +void pipe_free (struct pipe *pipe); + +/* ---------------------------------------------------------------- */ + +struct connq; +struct connq_request; + +/* Create a new listening queue, returning it in CQ. The resulting queue + will be of zero length, that is it won't allow connections unless someone + is already listening (change this with connq_set_length). */ +error_t connq_create (struct connq **cq); + +/* Wait for a connection attempt to be made on CQ, and return the connecting + socket in SOCK, and a request tag in REQ. If REQ is NULL, the request is + left in the queue, otherwise connq_request_complete must be called on REQ + to allow the requesting thread to continue. If NOBLOCK is true, + EWOULDBLOCK is returned when there are no immediate connections + available. */ +error_t connq_listen (struct connq *cq, int noblock, + struct connq_request **req, struct sock **sock); + +/* Return the error code ERR to the thread that made the listen request REQ, + returned from a previous connq_listen. */ +void connq_request_complete (struct connq_request *req, error_t err); + +/* Set CQ's queue length to LENGTH. Any sockets already waiting for a + connections that are past the new length will fail with ECONNREFUSED. */ +error_t connq_set_length (struct connq *cq, int length); + +/* Try to connect SOCK with the socket listening on CQ. If NOBLOCK is true, + then return EWOULDBLOCK immediately when there are no immediate + connections available. */ +error_t connq_connect (struct connq *cq, int noblock, struct sock *sock); + +/* ---------------------------------------------------------------- */ +/* Addresses */ + +struct addr +{ + struct port_info pi; + struct mutex lock; + + /* Which socket is at this address. */ + struct sock *sock; +}; + +/* Create a new address. */ +error_t addr_create (struct addr **addr); + +/* Set ADDR's socket to SOCK, possibly discarding a previous binding. */ +error_t addr_set_sock (struct addr *addr, struct sock *sock); + +/* ---------------------------------------------------------------- */ + +extern inline void +timestamp (time_value_t *stamp) +{ + host_get_time (mach_host_self (), stamp); +} + +#endif /* __PFLOCAL_H__ */ diff --git a/pflocal/sock.h b/pflocal/sock.h new file mode 100644 index 00000000..a858d019 --- /dev/null +++ b/pflocal/sock.h @@ -0,0 +1,294 @@ +/* A server for local sockets, of type PF_LOCAL + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by Miles Bader <miles@gnu.ai.mit.edu> + + 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, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef __PFLOCAL_H__ +#define __PFLOCAL_H__ + +/* ---------------------------------------------------------------- */ +/* Sockets */ + +/* A port on SOCK. Multiple sock_user's can point to the same socket. */ +struct sock_user +{ + struct port_info pi; + struct sock *sock; +}; + +/* An endpoint for a possible I/O stream. */ +struct sock +{ + int refs; + struct mutex lock; + + /* Reads from this socket come from READ_PIPE, writes go to WRITE_PIPE. + A sock always has a read pipe, and a write pipe when it's connected to + another socket. */ + struct pipe *read_pipe, *write_pipe; + + /* FLAGS from SOCK_*, below. */ + unsigned flags; + + /* An identifying number for the socket. */ + unsigned id; + /* Last time the socket got frobbed. */ + time_value_t change_time; + + /* This socket's local address. Note that we don't hold any references on + ADDR, and depend on the addr zeroing our pointer if it goes away (which + is ok, as we can then just make up another address if necessary, and no + one could tell anyway). */ + struct addr *addr; + + /* If this sock has been connected to another sock, then WRITE_ADDR is the + addr of that sock. We *do* hold a reference to this addr. */ + struct addr *write_addr; + + /* A connection queue to listen for incoming connections on. Once a socket + has one of these, it always does, and can never again be used for + anything but accepting incoming connections. */ + struct connq *connq; +}; + +/* Socket flags */ +#define SOCK_CONNECTED 0x1 /* A connected connection-oriented sock. */ +#define SOCK_NONBLOCK 0x2 /* Don't block on I/O. */ +#define SOCK_SHUTDOWN_READ 0x4 /* The read-half has been shutdown. */ +#define SOCK_SHUTDOWN_WRITE 0x8 /* The write-half has been shutdown. */ + +/* Returns the pipe that SOCK is reading from in PIPE, locked and with an + additional reference, or an error saying why it's not possible. NULL may + also be returned in PIPE with a 0 error, meaning that EOF should be + returned. SOCK mustn't be locked. */ +error_t sock_aquire_read_pipe (struct sock *sock, struct pipe **pipe); + +/* Returns the pipe that SOCK is writing to in PIPE, locked and with an + additional reference, or an error saying why it's not possible. SOCK + mustn't be locked. */ +error_t sock_aquire_write_pipe (struct sock *sock, struct pipe **pipe); + +/* Connect together the previously unconnected sockets SOCK1 and SOCK2. */ +error_t sock_connect (struct sock *sock1, struct sock *sock2) + +/* Return a new socket with the given pipe class in SOCK. */ +error_t sock_create (struct pipe_class *pipe_class, struct sock **sock); + +/* Return a new socket just like TEMPLATE in SOCK. */ +error_t sock_create (struct sock *template, struct sock **sock); + +/* Return a new user port on SOCK in PORT. */ +error_t sock_create_port (struct sock *sock, mach_port_t *port); + +/* ---------------------------------------------------------------- */ +/* Pipes */ + +/* A description of a class of pipes and how to operate on them. */ +struct pipe_class +{ + /* What sort of socket this corresponds too. */ + int sock_type; + + /* Flags, from PIPE_CLASS_*, below. */ + unsigned flags; + + /* Operations: */ + + /* Read from BUF into DATA &c. */ + error_t (*read)(void *buf, char **data, unsigned *data_len, unsigned amount); + /* Write DATA &c into BUF. */ + error_t (*write)(void *buf, char *data, unsigned data_len, unsigned *amount); + /* Return the number of readable characters in BUF. */ + unsigned (*readable)(void *buf); + /* Clear out any data. */ + error_t (*drain)(void *buf); + /* Initialize *BUF or return an error. */ + error_t (*init)(void **buf); + /* Cleanup BUF, freeing all resources. */ + void (*cleanup)(void *buf); +}; + +/* pipe_class flags */ +#define PIPE_CLASS_CONNECTIONLESS 0x1 /* A non-stream protocol. */ + +/* Some pre-defined pipe_classes. */ +struct pipe_class *stream_pipe_class; +struct pipe_class *dgram_pipe_class; +struct pipe_class *seqpacket_pipe_class; + +/* ---------------------------------------------------------------- */ + +/* A unidirectional data pipe; it transfers data from READER to WRITER. */ +struct pipe +{ + /* What kind of pipe we are. */ + struct pipe_class *class; + + /* We use this to keep track of active threads using this pipe, so that + while a thread is waiting to read from a pipe and that pipe gets + deallocated (say by socket_shutdown), it doesn't actually go away until + the reader realizes what happened. It is normally frobbed using + pipe_aquire & pipe_release, which do locking as well.. */ + unsigned refs; + + /* Various flags, from PIPE_* below. */ + unsigned flags; + + /* Various timestamps for this pipe. */ + time_value_t read_time; + time_value_t write_time; + + struct condition pending_reads; + struct condition pending_selects; + + struct mutex lock; + + /* When interrupt_operation is called on a socket, we want to wake up all + pending read threads, and have them realize they've been interrupted; + reads that happen after the interrupt shouldn't return EINTR. When a + thread waits on this pipe's PENDING_READS condition, it remembers this + sequence number; any interrupt bumps this number and broadcasts on the + condition. A reader thread will try to read from the pipe only if the + sequence number is the same as when it went to sleep. */ + unsigned long interrupt_seq_num; + + /* The actual data, and how to access it. */ + void *data; +}; + +/* Pipe flags. */ +#define PIPE_BROKEN 0x1 /* This pipe isn't connected. */ + +/* Lock PIPE and increment its ref count. */ +extern inline void +pipe_aquire (struct pipe *pipe) +{ + mutex_lock (&pipe->lock); + pipe->refs++; +} + +/* Decrement PIPE's (which should be locked) ref count and unlock it. If the + ref count goes to zero, PIPE will be destroyed. */ +extern inline void +pipe_release (struct pipe *pipe) +{ + if (--pipe->refs == 0) + pipe_free (pipe); + else + mutex_unlock (&pipe->lock); +} + +/* Returns the number of characters quickly readable from PIPE. */ +extern inline unsigned +pipe_readable (struct pipe *pipe) +{ + return (*pipe->class->readable)(pipe->data); +} + +/* Empty out PIPE of any data. */ +extern inline void +pipe_drain (struct pipe *pipe) +{ + (*pipe->class->drain)(pipe->data); +} + +/* Writes up to LEN bytes of DATA, to PIPE, and returns the amount written in + AMOUNT. If an error is returned, nothing is done. */ +error_t +pipe_write (struct pipe *pipe, char *data, unsigned len, unsigned *amount); + +/* Reads up to AMOUNT bytes from PIPE, which should be locked, into DATA, and + returns the amount written in LEN. If NOBLOCK is true, EWOULDBLOCK is + returned instead of block when no data is immediately available. If an + error is returned, nothing is done. */ +error_t pipe_read (struct pipe *pipe, int noblock, + char **data, unsigned *len, unsigned amount); + +/* Waits for PIPE to be readable, or an error to occurr. If NOBLOCK is true, + this operation will return EWOULDBLOCK instead of blocking when no data is + immediately available. */ +error_t pipe_wait (struct pipe *pipe, int noblock); + +/* Wake up all threads waiting on PIPE, which should be locked. */ +void pipe_kick (struct pipe *pipe); + +/* Creates a new pipe of class CLASS and returns it in RESULT. */ +error_t pipe_create (struct pipe_class *class, struct pipe **pipe); + +/* Free PIPE and any resources it holds. */ +void pipe_free (struct pipe *pipe); + +/* ---------------------------------------------------------------- */ + +struct connq; +struct connq_request; + +/* Create a new listening queue, returning it in CQ. The resulting queue + will be of zero length, that is it won't allow connections unless someone + is already listening (change this with connq_set_length). */ +error_t connq_create (struct connq **cq); + +/* Wait for a connection attempt to be made on CQ, and return the connecting + socket in SOCK, and a request tag in REQ. If REQ is NULL, the request is + left in the queue, otherwise connq_request_complete must be called on REQ + to allow the requesting thread to continue. If NOBLOCK is true, + EWOULDBLOCK is returned when there are no immediate connections + available. */ +error_t connq_listen (struct connq *cq, int noblock, + struct connq_request **req, struct sock **sock); + +/* Return the error code ERR to the thread that made the listen request REQ, + returned from a previous connq_listen. */ +void connq_request_complete (struct connq_request *req, error_t err); + +/* Set CQ's queue length to LENGTH. Any sockets already waiting for a + connections that are past the new length will fail with ECONNREFUSED. */ +error_t connq_set_length (struct connq *cq, int length); + +/* Try to connect SOCK with the socket listening on CQ. If NOBLOCK is true, + then return EWOULDBLOCK immediately when there are no immediate + connections available. */ +error_t connq_connect (struct connq *cq, int noblock, struct sock *sock); + +/* ---------------------------------------------------------------- */ +/* Addresses */ + +struct addr +{ + struct port_info pi; + struct mutex lock; + + /* Which socket is at this address. */ + struct sock *sock; +}; + +/* Create a new address. */ +error_t addr_create (struct addr **addr); + +/* Set ADDR's socket to SOCK, possibly discarding a previous binding. */ +error_t addr_set_sock (struct addr *addr, struct sock *sock); + +/* ---------------------------------------------------------------- */ + +extern inline void +timestamp (time_value_t *stamp) +{ + host_get_time (mach_host_self (), stamp); +} + +#endif /* __PFLOCAL_H__ */ |