Notes on jeffs socklib: file: /home/phil/Linux/libsrc/socklib/Notes Initialization: -sock_bind() calls find_dest that calls init_dest() to read in the mailbox file. - binding sets up the socket for you to receive things on. - The name/port can be in the mailbox file. This way people can contact you. - the name can be anonymous. In this case you need to send the name/port to people before they can contact you. I/O: - The read/write calls are done in sock_read and sock_write. All other routines go thru here. On error the socket is closed. - I/O Message format - 4 byte int holding message length followed by this many bytes (the 1st 4 bytes are not included in the message length). The message length is sent in network byte order. - Accepting new socket.. when we get a new socket on the listen socket, the first message we receive must be the mailbox name of the person making the socket connection. This is handled in accept_sock(). It will link the socket into our bound SOCK* linked list (by calling sock_connect(). - READS: -The maximum allowable read length is defined as a variable in bound struct: bufct. This is the maximum allowable bytes for a message. It is Used to check when we are out of sync. - The user passes in the buffer to read into (variable: message). It must have already been allocated. It should always be at least bufct bytes since the read will clip if the message length is > bufct bytes. The length of the current message buffer is not passed in. - Actually the read buffer should always be bufct+1 since it puts a null at msg[count] -If there is a read error, the socket is closed. Sockets that are closed get s->fd=-1. -2 is returned as status. - If things are ok, the fd that was just read is returned. -WRITES: sock_write - you pass in *SOCK. loop: - if the fd in SOCK has not yet been opened and we are not an anonymous socket.. - allocate socket, - bind any port number to it. - connect to address. - send message telling them our mailbox name. - It writes the message count followed by the message. - if there byte count sent does not equal the requeseted number of bytes then the socket is closed and the loop: is repeated (at most once). This tries to recover from things like computer reboots. SOCKET OPTS: - fcntl (F_SETFD,FD_CLOEXEC) close on exec` - sockopt so_reuseaddr - listen (max=5). SELECT: sock_sel() - calls sock_ssel().blocks waiting for message then reads. same as sock_ssel() but does not support the exclude sockets (ss) sock_ssel()-: select then read: : select on sockets in bound struct (including listen socket). : user can specifiy sockets in bound struct to ignore. these will not be included in the select. : user can specifiy extra sockets (p) to select on ` : select with timeout. : if listen socket then sock_accept() : if one of the p (extra) sockets, just return with the fd : call sock_read to read the message sock_fastsel: looks like same as sock_sel() except that the timeout is already in the time struct format rather than sec/usecs sock_only() : user specifies a SOCK struct to wait on. It then waits on only this and the listen socket. sock_poll() : ERRORS: -The routine ph->error() is called with the error message when an error returns. We always return from this call (unless the user does something funny with there own version of standard_error). -The default routine is standard_error() set in init. This just writes to stderr. You can change this destination with the routine sock_seterror(). -Errors in read/write will close the offending socket. This includes message lengths longer than the requested length (usually means you're out of sync). ------------------------------------------------------------------------------ STRUCTURES: ------------------------------------------------------------------------------ DEST: int dport port number char host[30] hostname (as in host file) char dname[30] service name. Users use this name as identifier. comes out of the mailbox file. SOCK: SOCK *next ptr to next SOCK (for linked list) DEST: *dest DEST info for this sock (who connected to us) fd int for this socket (-1 -->> closed) sin structaddr_in sin: sin.port.. passed to bind call. BOUND: int bind_fd; fd we bind for listening. DEST: *dest DEST struct for bound socket (bind_fd). SOCK: *head head of linked list of sockets we've done accepts on. struct sockaddr_in sin: sock addr for bind_fd. int bufct; max length for a message (excluding 4 byte length) default is 4096. All message buffers malloced by users should be at least this long (actually 4096+1). int interrupt; If true then sock_sel select will return with stat=-3 on an interrupt EINTR during the select wait. if 0 it keeps looping int isxview; 1 if xview ... int isaio ; 1 if aioread is turned on (solaris). int (*open)(struct SOCK *,int) called after accept or before connect if not null. user supplied. int (*close)(int fd) user supplied called before os close(). int (*error)(char *,char*) user supplied routine to call on error default is standard_error() which just prints to stderr. First arg is format string (printf) with at most a %s format descriptor. 2nd arg is the variable for %s or null. ----------------------------------------------------------------------------- How it is used: ------------------------------------------------------------------------------ To receive info: 0. The socklib.c code declares the globals: struct BOUND sock_bound and struct BOUND *bs = &sock_bound This is the root for all sockets. There is only 1 bound structure for each program. the top level is that programs listen socket, all socket connections from outside have socket structs linked in o the SOCK *next list. It uses stream sockets.. 1. A progran calls sock_bind (or bindsock for tk) with it's mail box name. It creates the listen socket with a socket() call, fills in the address info, calls bind on bs->bind_fd, fills in the bs-> dest address info for the listen socket and the calls listen(bs->bind_fd) 2. The user then calls accept_sock(0) (or maybe via sock_sel(). a. calls accept: b. reads the first message which should be: msgLen,mailBoxName of sender c. calls sock_connect(mbnameOfSender) to malloc a SOCK struct and link it into bs->next. Note this is not the normal socket connect() call. It just links the new socket into the bs->next list. d. It will call the open routine specifed (if specified) with (bs->open)(s,s->fd) where SOCK *s is the new SOCK entry. Note that there is one open routine for all sockets connected. 3. then sock_sel or sock_ssel to wait for input from all open sockets. To send info: ; 1. go through the bind for your own address. 2. If you are replying to a message: s=last_msg() will give SOCK struct of last caller else s=sock_connect(mbName); this will link the SOCK structure for this person into our bs->head. The fd is not yet open. endif sock_send(s,message). If s->fd < 0 then it will try to open a socket for us and link it in. It will do a bind any on this SOCK since we don't recieve on it. ----------------------------------------------------------------------------- Protocol: ------------------------------------------------------------------------------ 1. user wants to talk to cima. without socklib get port number for executive,computer connect() msg={int msglen, char *msg } switch message to network order write(fdex,message) .. ; need a mailbox name that cima knows about (adn the cpu??)