* SOCKET_H + /*--------- * Copyright (c) 1998,2001 Scott C. Klement + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + */ + *********************************************************************** *** Header file for doing sockets communications. *** *** To use this, you must /COPY RMTCALL/QRPGLESRC, SOCKET_H into *** the "D" specs of your RPG IV source member.... *** (or whatever the appropriate source lib/file, member is) *** *** Most of the major socket functions and structures are prototyped *** here. There may be some that I missed (because I havent needed *** them) if you need them, you'll have to add them yourself :) *** SCK 08/06/1998 ***********************************************************************   D/if defined(SOCKET_H) D/eof D/endif D/define SOCKET_H |
  *********************************************************************** ** C O N S T A N T S *********************************************************************** D IPVERSION C CONST(4)   ** Address families. D* Only Internet will be included for now... D* If you intend to use other than IP sockets D* you will have to add them in yourself. D* D AF_INET C CONST(2)   ** Socket Types: D* stream socket (TCP) D SOCK_STREAM C CONST(1) D* datagram socket (UDP) D SOCK_DGRAM C CONST(2) D* raw socket D SOCK_RAW C CONST(3)       ** Protocols... D* These are the commonly used protocols in D* the Internet Address Family. D* D* Internet Protocol D IPPROTO_IP C CONST(0) D* Transmission Control D* Protocol D IPPROTO_TCP C CONST(6) D* Unordered Datagram D* Protocol D IPPROTO_UDP C CONST(17) D* Raw Packets D IPPROTO_RAW C CONST(255) D* Internet Control D* Msg Protocol D IPPROTO_ICMP C CONST(1) D* socket layer D SOL_SOCKET C CONST(-1)     |
** IP-Level (IPPROTO_IP) options for setsockopt()/getsockopt() ** (Note: None of the multicast options are set here, but ** they probably should be) D* ip options D IP_OPTIONS C CONST(5) D* type of service D IP_TOS C CONST(10) D* time to live D IP_TTL C CONST(15) D* recv lcl ifc addr D IP_RECVLCLIFADDR... D C CONST(99)     ** TCP level (IPPROTO_TCP) options for setsockopt()/getsockopt() D* max segment size (MSS) D TCP_MAXSEG C 5 D* dont delay small packets D TCP_NODELAY C 10     ** Socket-Level (SOL_SOCKET) options for setsockopt()/getsockopt() D* allow broadcast msgs D SO_BROADCAST C 5 D* record debug information D SO_DEBUG C 10 D* just use interfaces, D* bypass routing D SO_DONTROUTE C 15 D* error status D SO_ERROR C 20 D* keep connections alive D SO_KEEPALIVE C 25 D* linger upon close D SO_LINGER C 30 D* out-of-band data inline D SO_OOBINLINE C 35 D* receive buffer size D SO_RCVBUF C 40 D* receive low water mark D SO_RCVLOWAT C 45 D* receive timeout value D SO_RCVTIMEO C 50 D* re-use local address |
D SO_REUSEADDR C 55 D* send buffer size D SO_SNDBUF C 60 D* send low water mark D SO_SNDLOWAT C 65 D* send timeout value D SO_SNDTIMEO C 70 D* socket type D SO_TYPE C 75 D* send loopback D SO_USELOOPBACK C 80     ** Types of Service for IP packets ** These are indended to be used in the 'ip' data structure ** defined below. D* normal D IPTOS_NORMAL C CONST(x'00') D* min cost D IPTOS_MIN C CONST(x'02') D* reliability D IPTOS_RELIABLE C CONST(x'04') D* throughput D IPTOS_THRUPUT C CONST(x'08') D* low-delay D IPTOS_LOWDELAY C CONST(x'10')     ** Precedence for Types of Service ** These are indended to be used in the 'ip' data structure ** defined below. D* net control D IPTOS_NET C CONST(x'E0') D* internet control D IPTOS_INET C CONST(x'C0') D* critic ecp D IPTOS_CRIT C CONST(x'A0') D* flash override D IPTOS_FOVR C CONST(x'80') D* flash D IPTOS_FLAS C CONST(x'60') D* immediate D IPTOS_IMME C CONST(x'40') D* priority |
D IPTOS_PTY C CONST(x'20') D* routine D IPTOS_ROUT C CONST(x'10')     ** I/O flags (for send, sendto, recv, recvfrom functions) D* dont route D MSG_DONTROUTE C CONST(1) D* out-of-band data D MSG_OOB C CONST(4) D* keep data in buffer D MSG_PEEK C CONST(8)     ** "Special" IP Address values D* any address available D INADDR_ANY C CONST(0) D* broadcast D INADDR_BROADCAST... D C CONST(4294967295) D* loopback/localhost D INADDR_LOOPBACK... D C CONST(2130706433) D* no address exists D INADDR_NONE C CONST(4294967295)   ** ICMP message types D* echo reply D ICMP_ECHOR C CONST(x'00') D* unreachable D ICMP_UNREA C CONST(x'03') D* source quench D ICMP_SRCQ C CONST(x'04') D* redirect D ICMP_REDIR C CONST(x'05') D* echo D ICMP_ECHO C CONST(x'08') D* time exceeded D ICMP_TIMX C CONST(x'0B') D* parameter problem D ICMP_PARM C CONST(x'0C') D* timestamp request D ICMP_TSTP C CONST(x'0D') D* timestamp req reply |
D ICMP_TSTPR C CONST(x'0E') D* info request D ICMP_IREQ C CONST(x'0F') D* info request reply D ICMP_IREQR C CONST(x'10') D* addr mask request D ICMP_MASK C CONST(x'11') D* addr mask req reply D ICMP_MASKR C CONST(x'12')   ** ICMP subtype codes D* network unreachable D UNR_NET C CONST(x'00') D* host unreachable D UNR_HOST C CONST(x'01') D* protocol unreachble D UNR_PROTO C CONST(x'02') D* port unreachable D UNR_PORT C CONST(x'03') D* fragmentation needed D* and dont fragment D* flag is set D UNR_FRAG C CONST(x'04') D* source route failed D UNR_SRCF C CONST(x'05') D* time exceeded in D* transit D TIMX_INTRA C CONST(x'00') D* time exceeded in D* frag reassembly D TIMX_REASS C CONST(x'01') D* redir for network D REDIR_NET C CONST(x'00') D* redir for host D REDIR_HOST C CONST(x'01') D* redir for TOS & Net D REDIR_TOSN C CONST(x'02') D* redir for TOS & Host D REDIR_TOSH C CONST(x'03')   D/if not defined(FCNTL_CONSTANTS) ** fcntl() commands D F_DUPFD C CONST(0) D F_GETFL C CONST(6) |
D F_SETFL C CONST(7) D F_GETOWN C CONST(8) D F_SETOWN C CONST(9)   ** fcntl() flags D O_NONBLOCK C CONST(128) D O_NDELAY C CONST(128) D FNDELAY C CONST(128) D FASYNC C CONST(512) D/define FCNTL_CONSTANTS D/endif   *********************************************************************** ** D A T A S T R U C T U R E S ** ** Note that data structures here are all set up to be based on ** a pointer. The reason for this is: ** 1) Data structs that you don't use in your program won't ** have memory allocated to them. ** 2) You can have different "instances" of each data struct ** simply by moving the pointer to a different area of ** memory. *********************************************************************** ** Socket Address (Generic, for any network type) ** ** struct sockaddr { ** u_short sa_family; ** char sa_data[14]; ** }; ** D p_sockaddr S * D SockAddr DS based(p_sockaddr) D SA_Family 5U 0 D SA_Data 14A     ** Socket Address (Internet) ** ** struct sockaddr_in { ** short sin_family; ** u_short sin_port; ** struct in_addr sin_addr; ** char sin_zero[8]; ** }; |
** D sockaddr_in DS based(p_sockaddr) D sin_Family 5I 0 D sin_Port 5U 0 D sin_addr 10U 0 D sin_zero 8A     ** ** Host Database Entry (for DNS lookups, etc) ** ** (this is a partial implementation... didn't try to ** figure out how to deal with all possible addresses ** or all possible aliases for a host in RPG) ** ** struct hostent { ** char *h_name; ** char **h_aliases; ** int h_addrtype; ** int h_length; ** char **h_addr_list; ** }; ** ** #define h_addr h_addr_list[0] ** D p_hostent S * D hostent DS Based(p_hostent) D h_name * D h_aliases * D h_addrtype 5I 0 D h_length 5I 0 D h_addrlist * D p_h_addr S * Based(h_addrlist) D h_addr S 10U 0 Based(p_h_addr)     ** ** Service Database Entry (which service = which port, etc) ** ** struct servent { ** char *s_name; ** char **s_aliases; ** int s_port; ** char *s_proto; |
** }; ** D p_servent S * D servent DS Based(p_servent) D s_name * D s_aliases * D s_port 10I 0 D s_proto *     ** ** IP structure without any opts (for RAW sockets) ** ** struct ip { ** unsigned ip_v:4; Version (first 4 bits) ** unsigned ip_hl:4; Header length (next 4) ** u_char ip_tos; Type of service ** short ip_len; Total Length ** u_short ip_id; Identification ** short ip_off; Fragment offset field ** u_char ip_ttl; Time to live ** u_char ip_p; Protocol ** u_short ip_sum; Checksum ** struct in_addr ip_src; Source Address ** struct in_addr ip_dst; Destination Address ** }; ** ** Note: Since you can't define a variable to be 4 bits long ** in RPG, ip_v_hl is a combination of ip_v and ip_hl. ** with mult/div/mvr and data structures, it should still ** be usable... ** ** Since ip_tos & ip_ttl conflict with the definitions for ** setsockopt() & getsockopt(), we add an extra $ to the end... d p_ip S * D ip DS based(p_ip) D ip_v_hl 1A D ip_tos$ 1A D ip_len 5I 0 D ip_id 5U 0 D ip_off 5I 0 D ip_ttl$ 1A D ip_p 1A D ip_sum 5U 0 |
D ip_src 10U 0 D ip_dst 10U 0     ** ** UDP Packet Header (for RAW sockets) ** ** struct udphdr { /* UDP header */ ** u_short uh_sport; /* source port */ ** u_short uh_dport; /* destination port */ ** short uh_ulen; /* UDP length */ ** u_short uh_sum; /* UDP checksum */ ** }; ** d p_udphdr S * d udphdr DS based(p_udphdr) D uh_sport 5U 0 D uh_dport 5U 0 D uh_ulen 5I 0 D uh_sum 5U 0     ** Internet Control Message Protocol (ICMP) header ** (I THINK I did the unions correctly... but you might want to ** check that out if you're having problems...) ** ** struct icmp { /* ICMP header */ ** u_char icmp_type; /* ICMP message type */ ** u_char icmp_code; /* type sub code */ ** u_short icmp_cksum; /* ICMP checksum */ ** union { /* Message type substructures:*/ ** u_char ih_pptr; /* Parameter problem pointer*/ ** struct in_addr ih_gwaddr; /* Redirect gateway address */ ** struct ih_idseq { /* Echo/Timestmp Req/Reply */ ** u_short icd_id; /* Indentifier */ ** u_short icd_seq; /* Sequence number */ ** } ih_idseq; ** int ih_void; /* Unused part of some msgs */ ** } icmp_hun; ** union { ** struct id_ts { /* Timestamp substructure */ ** u_long its_otime; /* Originate timestamp */ ** u_long its_rtime; /* Receive timestamp */ ** u_long its_ttime; /* Transmit timestamp */ |
** } id_ts; ** struct id_ip { /* Imbedded 'original' IP hdr */ ** struct ip idi_ip; /* in ICMP error-type msgs. */ ** /* Includes IP header,IP opts,*/ ** /* and 64 bits of data. */ ** } id_ip; ** u_long id_mask; /* Address mask request/reply */ ** char id_data[1]; /* Beginning of echo req data */ ** } icmp_dun; ** }; D p_icmp S * D icmp DS based(p_icmp) D icmp_type 1A D icmp_code 1A D icmp_cksum 5U 0 D icmp_hun 4A D ih_gwaddr 10U 0 OVERLAY(icmp_hun:1) D ih_pptr 1A OVERLAY(icmp_hun:1) D ih_idseq 4A OVERLAY(icmp_hun:1) D icd_id 5U 0 OVERLAY(ih_idseq:1) D icd_seq 5U 0 OVERLAY(ih_idseq:3) D ih_void 5I 0 OVERLAY(icmp_hun:1) D icmp_dun 20A D id_ts 12A OVERLAY(icmp_dun:1) D its_otime 10U 0 OVERLAY(id_ts:1) D its_rtime 10U 0 OVERLAY(id_ts:5) D its_ttime 10U 0 OVERLAY(id_ts:9) D id_ip 20A OVERLAY(icmp_dun:1) D idi_ip 20A OVERLAY(id_ip:1) D id_mask 10U 0 OVERLAY(icmp_dun:1) D id_data 1A OVERLAY(icmp_dun:1)     ** ** Time Value Structure (for the select() function, etc) ** ** struct timeval { ** long tv_sec; /* seconds */ ** long tv_usec; /* microseconds */ ** }; ** ** contrains a structure for specifying a wait time on ** a select() function... ** |
** tv_sec = seconds. tv_usec = microseconds ** D p_timeval S * D timeval DS based(p_timeval) D tv_sec 10I 0 D tv_usec 10I 0     ** linger structure (used with setsockopt or getsockopt) ** ** struct linger { ** int l_onoff; /* Option Setting ON/OFF */ ** int l_linger; /* Time to linger in seconds */ ** }; ** D p_linger S * D linger DS BASED(p_linger) D l_onoff 10I 0 D l_linger 10I 0     *********************************************************************** ** S U B P R O C E D U R E P R O T O T Y P E S *********************************************************************** ** -------------------------------------------------------------------- ** ** socket--Create Socket ** ** int socket(int address_family, ** int type, ** int protocol) ** ** ** The socket() function is used to create an end point for ** communications. The end point is represented by the ** socket descriptor returned by the socket() function. ** ** -------------------------------------------------------------------- D socket PR 10I 0 ExtProc('socket') D AddrFamily 10I 0 Value D SocketType 10I 0 Value D Protocol 10I 0 Value     |
** -------------------------------------------------------------------- ** ** setsockopt()--Set Socket Options ** ** int setsockopt(int socket_descriptor, ** int level, ** int option_name, ** char *option_value ** int option_length) ** ** The setsockopt() function is used to set socket options ** (there are many, see the book.) ** -------------------------------------------------------------------- D setsockopt PR 10I 0 ExtProc('setsockopt') D SocketDesc 10I 0 Value D Opt_Level 10I 0 Value D Opt_Name 10I 0 Value D Opt_Value * Value D Opt_Len 10I 0 Value     ** -------------------------------------------------------------------- ** getsockopt() -- Retrieve Info about Socket Options ** ** int getsockopt(int socket_descriptor, ** int level, ** int option_name, ** char *option_value, ** int *option_length) ** ** Gets various information about the socket's options. ** (there are many, see the book.) ** -------------------------------------------------------------------- D getsockopt PR 10I 0 extproc('getsockopt') D SocketDesc 10I 0 VALUE D Opt_Level 10I 0 VALUE D Opt_Name 10I 0 VALUE D Opt_Value * VALUE D Opt_Length 10I 0     ** -------------------------------------------------------------------- ** ** getsockname()--Get Local Address for Socket |
** ** int getsockname(int socket_descriptor, ** struct sockaddr *local_address, ** int *address_length) ** ** struct sockaddr { ** u_short sa_family; ** char sa_data[14]; ** }; ** ** The getsockname() function is used to retreive the local address ** asociated with a socket. ** -------------------------------------------------------------------- D getsockname PR 10I 0 ExtProc('getsockname') D SocketDesc 10I 0 Value D SockAddr like(Sockaddr_in) D AddrLength 10I 0     ** ** -------------------------------------------------------------------- ** ** getpeername()--Retrieve Destination Address of Socket ** ** int getpeername(int socket_descriptor, ** struct sockaddr *local_address, ** int *address_length) ** ** struct sockaddr { ** u_short sa_family; ** char sa_data[14]; ** }; ** ** ** The getpeername() function is used to retreive the destination ** address to which the socket is connected. ** ** Note: Socket must be connected first. ** ** -------------------------------------------------------------------- D getpeername PR 10I 0 ExtProc('getpeername') D SocketDesc 10I 0 Value D p_sockaddr * Value D AddrLength 10I 0 |
    ** -------------------------------------------------------------------- ** bind()--Bind socket to specified adapter and/or port ** ** int bind(int socket_descriptor,   ** struct sockaddr *local_address, ** int address_length) ** ** struct sockaddr { ** u_short sa_family; ** char sa_data[14]; ** }; ** ** ** The bind() function is used to associate a local address ** and port with a socket. This allows you to get only ** socket requests on a specific network adapter, and to ** assign a specific port to your socket. ** For example, if you're writing a telnet server, you'd ** bind to port 23, because thats the standard port for ** telnets to listen on. ** If we bind to an address of 0, it will allow requests on ** any (TCP/IP enabled) network adapter. ** ** -------------------------------------------------------------------- D bind PR 10I 0 ExtProc('bind') D Sock_Desc 10I 0 Value D p_Address * Value D AddressLen 10I 0 Value     ** -------------------------------------------------------------------- ** listen()--Invite Incoming Connections Requests ** ** int listen(int socket_descriptor, ** int back_log) ** ** ** The listen() function is used to indicate a willingness to accept ** incoming connection requests. if a listen() is not done, ** incoming requests are refused. ** |
** -------------------------------------------------------------------- D listen PR 10I 0 ExtProc('listen') D SocketDesc 10I 0 Value D Back_Log 10I 0 Value     ** -------------------------------------------------------------------- ** accept()--Wait for Connection Request and Make Connection ** ** int accept(int socket_descriptor, ** struct sockaddr *address, ** int *address_length) ** ** struct sockaddr { ** u_short sa_family; ** char sa_data[14]; ** }; ** ** The accept() function is used to wait for connection requests. ** accept() takes the first connection request on the queue of ** pending connection requests and creates a new socket to service ** the connection request. ** ** -------------------------------------------------------------------- D accept PR 10I 0 ExtProc('accept') D Sock_Desc 10I 0 Value D p_Address * Value D p_AddrLen 10I 0 options(*omit)     ** -------------------------------------------------------------------- ** connect() -- Connect to a host. ** ** int connect(int socket_descriptor, ** struct sockaddr *destination, ** int address_length) ** ** Used to connect to a host. (Usually used on the client-side) ** In TCP applications, this takes an address & port and connects ** to a server program thats listening on that port. In UDP ** this simply specifies the address & port to send to. ** ** -------------------------------------------------------------------- D connect PR 10I 0 ExtProc('connect') |
D Sock_Desc 10I 0 VALUE D p_SockAddr * VALUE D AddressLen 10I 0 VALUE     ** -------------------------------------------------------------------- ** send()--Send Data ** ** int send(int socket_descriptor, ** char *buffer, ** int buffer_length, ** int flags) ** ** Sends data in buffer via socket connection to another program. ** ** In the case of text, it should be converted to ASCII and then ** CR/LF terminated. ** ** -------------------------------------------------------------------- D Send PR 10I 0 ExtProc('send') D Sock_Desc 10I 0 Value D p_Buffer * Value D BufferLen 10I 0 Value D Flags 10I 0 Value     ** -------------------------------------------------------------------- ** sendto()--Send Data ** ** int sendto(int socket_descriptor, ** char *buffer, ** int buffer_length, ** int flags, ** struct sockaddr *destination_address, ** int address_length) ** ** Sends data in buffer via connected/connectionless sockets ** ** This is more useful for connectionless sockets (such as UDP) ** because allows you to specify the destination address. ** ** When used with a connection-oriented sockets (such as TCP) ** the destination address should be set to *NULL, and the length ** should be zero. |
** ** -------------------------------------------------------------------- D SendTo PR 10I 0 ExtProc('sendto') D Sock_Desc 10I 0 Value D p_Buffer * Value D BufferLen 10I 0 Value D Flags 10I 0 Value D DestAddr * Value D AddrLen 10I 0 Value     ** -------------------------------------------------------------------- ** recv()--Receive Data ** ** int recv(int socket_descriptor, I ** char *buffer, I ** int buffer_length, I ** int flags) ** ** ** The recv() funcion is used to receive data through a socket. ** ** -------------------------------------------------------------------- D Recv PR 10I 0 ExtProc('recv') D Sock_Desc 10I 0 Value D p_Buffer * Value D BufferLen 10I 0 Value D Flags 10I 0 Value     ** -------------------------------------------------------------------- ** recvfrom()--Receive Data w/From Address ** ** int recvfrom(int socket_descriptor, ** char *buffer, ** int buffer_length, ** int flags, ** struct sockaddr *from_address, ** int *address_length) ** ** ** The recvfrom() function receives data through a connected, or ** an unconnected socket. ** |
** This is particularly useful for UDP/Connectionless sockets ** because it allows you to ascertain who sent the data to you. ** ** The from_address and address_length parms are ignored on ** connection-oriented sockets -- or if they are set to *NULL. ** -------------------------------------------------------------------- D RecvFrom PR 10I 0 ExtProc('recvfrom') D Sock_Desc 10I 0 Value D p_Buffer * Value D BufferLen 10I 0 Value D Flags 10I 0 Value D FromAddr * Value D AddrLength 10I 0     ** -------------------------------------------------------------------- ** close()--End Socket Connection ** ** int close(int descriptor) ** ** Ends a socket connection, and deletes the socket descriptor. ** ** Note: Due to conflicts with IFSIO_H, we are only defining ** close() if it has not already been defined. ** -------------------------------------------------------------------- D/if not defined(CLOSE_PROTOTYPE) D Close PR 10I 0 ExtProc('close') D Sock_Desc 10I 0 Value D/define CLOSE_PROTOTYPE D/endif     ** -------------------------------------------------------------------- ** shutdown()-- disable reading/writing on a socket ** ** int shutdown(int descriptor, ** int how) ** ** Stops all reading and/or writing on a socket. ** Difference between this and close() is that with close, you ** actually delete the descriptor, and must accept() a new one, ** or allocate (socket()) a new one. ** ** The how parameter can be: |
** 0 = no more data can be received ** 1 = no more data can be sent ** 2 = no more data can be sent or received ** ** -------------------------------------------------------------------- D shutdown PR 10I 0 ExtProc('shutdown') D Sock_Desc 10I 0 Value D How 10I 0 Value     ** -------------------------------------------------------------------- ** select() -- wait for events on multiple sockets ** ** int select(int max_descriptor, ** fd_set *read_set, ** fd_set *write_set, ** fd_set *exception_set, ** struct timeval *wait_time) ** ** Select is used to wait for i/o on multiple sockets. This ** prevents your job from "blocking" on one socket read, while ** there is data to read on another socket. ** ** It also allows you to "poll" for data to be found on a socket ** and to set a timeout value to keep your application from ** stopping forever on a "dead-end" socket. ** ** ***** To help with managing the descriptor sets, I have ** ***** created FD_SET, FD_ISSET, FD_CLR and FD_ZERO functions ** ***** in my SOCKUTIL_H/SOCKUTILR4 socket utilities functions! ** ** max_desriptor = The number of descriptors in your sets. ** (take the highest descriptor value you want ** to wait on, and add 1, and put it here) ** ** read_set = A 28-byte character field specifying, on input, ** which descriptors to wait for, and, on output, ** which descriptors have data waiting on them. ** This can be set to *NULL if you do not wish to ** wait for any sockets to be read. ** ** write_set = A 28-byte character field specifying, on input, ** which descriptors to wait for, and, on output, ** which descriptors are ready to be written to. |
** This can be set to *NULL if you do not wish to ** wait for any sockets to be written to. ** ** exception_set = A 28-byte character field specifying, on input, ** which descriptors to test, and on output, ** which descriptors have exceptions signalled to them. ** This can be set to *NULL if you do not wish to ** check for any sockets to have exceptions. ** ** NOTE: An exception is not the same as an error. ** Exceptions are usually out-of-band data! ** ** wait_time = a timeval data structure containing the amoutn of ** time to wait for an event to occur. ** If a wait time of zero is given, select() will ** return immediately. ** If *NULL is passed instead of the timeval structure, ** select() will wait indefinitely. ** ** Returns the number of descriptors that met selection criteria ** or 0 for timeout ** or -1 for error. ** -------------------------------------------------------------------- D Select PR 10I 0 extproc('select') D max_desc 10I 0 VALUE D read_set * VALUE D write_set * VALUE D except_set * VALUE D wait_Time * VALUE     ** -------------------------------------------------------------------- ** givedescriptor() -- Pass Descriptor Access to Another Job ** ** int givedescriptor(int descriptor, ** char *target_job) ** ** Allows you to pass a descriptor from one OS/400 job to another. ** (Very useful if you wanted one job to wait for incoming conn. ** then, submit a seperate job to deal with each client connection   ** while the original keeps waiting for more) ** ** It is the programmer's responsibility to alert the target job |
** that it needs to take the descriptor, using takedescriptor(). ** ** the info for the target job can be obtained by calling a Work ** Managment API that supplies an "internal job identifier" ** (such as QUSRJOBI) ** ** returns 0 = success, -1 = failure ** -------------------------------------------------------------------- D givedescriptor PR 10I 0 extproc('givedescriptor') D SockDesc 10I 0 VALUE D Target_Job * VALUE     ** -------------------------------------------------------------------- ** takedescriptor() -- Receive Descriptor Access from Another Job ** ** int takedescriptor(char *source_job) ** ** Allows you to pass a descriptor from one OS/400 job to another. ** (Very useful if you wanted one job to wait for incoming conn. ** then, submit a seperate job to deal with each client connection ** while the original keeps waiting for more) ** ** the info for the source job can be obtained by calling a Work ** Managment API that supplies an "internal job identifier" ** (such as QUSRJOBI). ** ** You can also specify *NULL pointer for the Source_Job parm if ** you want to receive a descriptor from ANY job that gives one ** one to you. ** ** If no other jobs has referenced yours with givedescriptor() ** then this function will block. ** ** return value is the socket descriptor taken, or -1 for error. ** -------------------------------------------------------------------- D takedescriptor PR 10I 0 extproc('takedescriptor') D Source_Job * VALUE     ** -------------------------------------------------------------------- ** gethostbyname() -- Resolves a domain name to an IP address ** ** struct hostent *gethostbyname(char *host_name) |
** ** struct hostent { ** char *h_name; ** char **h_aliases; ** int h_addrtype; ** int h_length; ** char **h_addr_list; ** }; ** ** Returns a pointer to a host entry structure. The aliases and ** address list items in the structure are pointers to arrays of ** pointers, which are null terminated. ** ** Note: The strings & arrays used in C are often variable length, ** null-terminated entities. Be careful to only use bytes from ** the returned pointers (in the hostent data structure) to ** the first null (x'00') character. ** -------------------------------------------------------------------- D gethostbyname PR * extProc('gethostbyname') D HostName * value options(*string)     ** -------------------------------------------------------------------- ** getservbyname()--Get Port Number for Service Name ** ** struct servent *getservbyname(char *service_name, ** char *protocol_name) ** ** struct servent { ** char *s_name; ** char **s_aliases; ** int s_port; ** char *s_proto; ** }; ** ** This is generally used to look up which port is used for a given ** internet service. i.e. if you want to know the port for ** TELNET, you'd do x = getservbyname('telnet': 'tcp') ** -------------------------------------------------------------------- D getservbyname PR * extproc('getservbyname') D service_name * value options(*string) D protocol_nam * value options(*string)     |
** -------------------------------------------------------------------- ** gethostbyaddr()--Get Host Information for IP Address ** ** struct hostent *gethostbyaddr(char *host_address, ** int address_length, ** int address_type) ** struct hostent { ** char *h_name; ** char **h_aliases; ** int h_addrtype; ** int h_length; ** char **h_addr_list; ** }; ** ** An IP address (32-bit integer formnat) goes in, and a ** hostent structure pops out. Really, kinda fun, if you ** havent already learned to hate the hostent structure, that is. ** ** Note: The strings & arrays used in C are often variable length, ** null-terminated entities. use caution to only use data from ** the returned pointer up until the terminating null (x'00') ** ** -------------------------------------------------------------------- D gethostbyaddr PR * ExtProc('gethostbyaddr') D IP_Address 10U 0 D Addr_Len 10I 0 VALUE D Addr_Fam 10I 0 VALUE     ** -------------------------------------------------------------------- ** inet_addr()--Converts an address from dotted-decimal format ** to a 32-bit IP address. ** ** unsigned long inet_addr(char *address_string) ** ** Converts an IP address from format 192.168.0.100 to an ** unsigned long, such as hex x'C0A80064'. ** ** returns INADDR_NONE on error. ** ** KNOWN BUG: Due to the fact that this can't return a negative value, ** it returns x'FFFFFFFF' on error. However, x'FFFFFFFF' ** is also the correct IP for the valid address of ** "255.255.255.255". (which is "worldwide broadcast") |
** A reasonable workaround is to check for 255.255.255.255 ** beforehand, and translate it manually rather than ** calling inet_addr. ** -------------------------------------------------------------------- D inet_addr PR 10U 0 ExtProc('inet_addr') D char_addr * value options(*string)       ** -------------------------------------------------------------------- ** inet_ntoa()--Converts an address from 32-bit IP address to ** dotted-decimal format. ** ** char *inet_ntoa(struct in_addr internet_address) ** ** Converts from 32-bit to dotted decimal, such as, x'C0A80064' ** to '192.168.0.100'. Will return NULL on error ** ** Note: The strings & arrays used in C are often variable length, ** null-terminated entities. Make sure you only use bytes from ** the returned pointer to the first null (x'00') character. ** ** -------------------------------------------------------------------- D inet_ntoa PR * ExtProc('inet_ntoa') D ulong_addr 10U 0 VALUE     ** -------------------------------------------------------------------- ** fcntl()--Change Descriptor Attributes ** ** int fcntl(int descriptor, int command, ...) ** ** The third parameter (when used with sockets) is also an ** integer passed by value.. it specifies an argument for ** some of the commands. ** ** commands supported in sockets are: ** F_GETFL -- Return the status flags for the descriptor ** F_SETFL -- Set status flags for the descriptor ** (Arg =)status flags (ORed) to set. ** (the commands below arent terribly useful in RPG) ** F_DUPFD -- Duplicate the descriptor ** (Arg =)minimum value that new descriptor can be ** F_GETOWN -- Return the process ID or group ID that's |
** set to receive SIGIO & SIGURG ** F_SETOWN -- Set the process ID or group ID that's ** to receive SIGIO & SIGURG ** (Arg =)process ID (or neg value for group ID) ** ** returns -1 upon error. ** successful values are command-specific. ** -------------------------------------------------------------------- D/if not defined(FCNTL_PROTOTYPE) D fcntl PR 10I 0 ExtProc('fcntl') D SocketDesc 10I 0 Value D Command 10I 0 Value D Arg 10I 0 Value Options(*NOPASS) D/define FCNTL_PROTOTYPE D/endif |