Für diese Funktionalität werden neue Subfunktionen für sendmsg(), recvmsg(), setsockopt() und getsockopt() zur Verfügung gestellt.
Dazu sind folgende Strukturen in der Include-Datei sys.socket.h notwendig:
/* * struct instead of cmsghdr in case of Handoff-Handling */ struct red_info_tcp { short fd; /* file descriptor (listener) */ short port; /* port number */ short domain; /* address family */ short flags; /* flags of success */ int cid; /* cid */ int if_index; /* interface index listener process */ int rwindow; /* max read window */ int wwindow; /* max write window */ }; struct red_info_iso { short fd; /* file descriptor (listener) */ short domain; /* address family */ short flags; /* flags of success */ short tsellen; /* length of TSEL */ int rwindow; /* max read window */ int wwindow; /* max write window */ char tsel[32]; /* TSEL application */ char tesn[8]; /* TESN hostname */ }; struct red_info_svrs { short domain; /* domain (server[accept]) */ short fd_server; /* file descriptor(server[accept]) */ int tsor_server; /* tsap_open_reference 1. server_socket */ int cref_server; /* cref server[accept]_socket */ }; struct cmsg_redhdr { u_int cmsg_len; /* data byte count, including hdr */ int cmsg_level; /* originating protocol */ int cmsg_type; /* protocol-specific type of operation */ union { char tsap_name[TSAPNAMMAXLEN]; /* needed tsap_name for shared tsap */ struct red_info_iso red_liso; /* needed tsap_name for iso shared tsap */ struct red_info_tcp red_ltcp; /* Info of listen socket */ struct red_info_tcp red_ctcp; /* Info of client */ struct red_info_svrs red_svrs; /* Info of server socket ("accept") */ } cmsg_redhdr_info; short bind_ok; /* open shared TSAP successfull */ short handoff_ok; /* handoff successfull */ short tsap_name_len; /* length of tsap_name */ short fd_server; /* file descriptor redirected socket */ short domain; /* address family */ int tsn; /* tsn server-process */ #define redhdr_tsap_name cmsg_redhdr_info.tsap_name #define redhdr_red_liso cmsg_redhdr_info.red_liso #define redhdr_red_ltcp cmsg_redhdr_info.red_ltcp #define redhdr_red_ctcp cmsg_redhdr_info.red_ctcp #define redhdr_red_svrs cmsg_redhdr_info.red_svrs };
Ablaufreihenfolge
Annahme: Client = C, Listener = L, Server = S
Der Listen-Socket des Listeners L hat den File-Deskriptor fd = 1.
Zwischen Listener L und Server S wird eine Verbindung unter der Domäne AF_ISO aufgebaut, mit dem fd 0 auf der L-Seite und dem fd 0 auf der S-Seite. Diese Verbindung kann sowohl im Blocking- als auch im Nonblocking-Modus aufgebaut werden.
Im Nonblocking-Modus ist es zwingend erforderlich, dass die ausstehenden Ereignisse mitselect() oder soc_poll() abgefragt werden.
Der AF_ISO Listen-Socket auf der S-Seite hat den fd 0. Das Verschieben läuft in folgenden Schritten ab:
C baut eine Verbindung zu L auf.
Die Verbindung wird von L angenommen und nach S verschoben.
In L wird mit sendmsg() über die lokale AF_ISO-Verbindung die Information über die Domäne der von C aufgebauten Verbindung und der fd des Accept-Sockets dieser Verbindung an S weitergegeben.
int sendmsg(int s, struct msghdr * msg, int flags);
msg.msg_control ist ein Zeiger auf eine Struktur vom Typ cmsg_redhdr.
In msg.msg_control_len wird die Länge der struct cmsg_redhdr eingetragen.
cmsg_redhdr.cmsg_len = sizeof(cmsg_redhdr)
cmsg_redhdr.cmsg_level = SOL_TRANSPORT
cmsg_redhdr.cmsg_type = TPOPT_REDI_DATAIn cmsg_redhdr.domain muss die Adressfamilie des zu verschiebenden Endpunkts und in Abhängigkeit von dieser Adressfamilie der fd des Accept-Sockets in cmsg_redhdr.redhdr_red_liso (bei AF_ISO) oder cmsg_redhdr.redhdr_red_ltcp (bei AF_INET oder AF_INET6) im Element fd eingetragen werden.
Auf der S-Seite wird mit recvmsg() auf der AF_ISO Verbindung gelesen.
int recvmsg(int s, struct msghdr * msg, int flags);
msg.msg_control ist ein Zeiger auf eine Strukur vom Typ cmsg_redhdr
cmsg_redhdr.cmsg_len = sizeof(cmsg_redhdr)
cmsg_redhdr.cmsg_level = SOL_TRANSPORT
cmsg_redhdr.cmsg_type = TPOPT_REDI_DATAAktion auf S:
Mit der Information von L, die in der übergebenen Strukur vom Typ cmsg_redhdr enthalten ist, wird durch einen internen bind() ein neuer Verbindungsendpunkt erzeugt.Der fd dieses Endpunktes wird im Feld cmsg_redhdr.fd_server zusammen mit der Adressfamilie in cmsg_redhdr.domain als Returnwert übergeben.
Von der S-Seite wird an die L-Seite die Information gesandt, dass der neue Verbindungsendpunkt erfolgreich erstellt wurde.
int sendmsg(int s, struct msghdr * msg, int flags);
msg.msg_control ist ein Zeiger auf eine Strukur vom Typ cmgs_redhdr
cmsg_redhdr.cmsg_ len = sizeof(cmsg_redhdr)
cmsg_redhdr.cmsg_level = SOL_TRANSPORT
cmsg_redhdr.cmsg_type = TPOPT_REDI_BDOKZusätzlich muss in cmsg_redhdr.domain die Adressfamilie des Sockets für den neuen Endpunkt und in cmsg_redhdr.fd_server der fd dieses Sockets eingetragen werden.
Auf der L-Seite muss auf die Information, dass der neue Endpunkt vorhanden ist, gewartet werden, bevor die eigentliche Verschiebung ausgeführt werden kann.
int recvmsg(int s, struct msghdr * msg, int flags);
msg.msg_control ist ein Zeiger auf eine Strukur vom Typ cmsg_redhdr
cmsg_redhdr.cmsg.len = sizeof(struct cmsg_redhdr)
cmsg_redhdr.cmsg_level = SOL_TRANSPORT
cmsg_redhdr.cmsg_type = TPOPT_REDI_BDOKZusätzlich muss in cmsg_redhdr.domain die Adressfamilie des zu verschiebenden Endpunkts und in Abhängigkeit von dieser Adressfamilie der fd des Accept-Sockets in cmsg_redhdr.redhdr_red_liso (bei AF_ISO) oder cmsg_redhdr.redhdr_red_ltcp (bei AF_INET oder AF_INET6) im Element fd eingetragen werden.
Im Feld cmsg_redhdr.bind_ok kann überprüft werden, ob mit dem Wert REDBIND_OK das erfolgreiche Einrichten des neuen Endpunktes auf der S-Seite quittiert wird.
Intern wird jetzt ein Datenstopp für diesen Verbindungsendpunkt ausgelöst, d.h. es können vom Client Daten gesendet werden, sie werden jedoch nicht mehr an den alten Verbindungsendpunkt zugestellt.
Durch setsockopt() auf der L-Seite wird die Funktionalität des Endpunktes verschoben, d.h. die im Accept-Socket eingetragenen Partner-Informationen werden an den Socket des neuen Endpunkts im Server übertragen.
int setsockopt(int s, int level, int optname, char * optval, int optlen);
optval ist ein Zeiger auf eine Strukur vom Typ cmsg_redhdr
level = SOL_TRANSPORT
optname = TPOPT_REDI_CALLcmsg_redhdr.cmsg_len = sizeof(struct cmsg_redhdr)
cmsg_redhdr.cmsg_level = SOL_TRANSPORT
cmsg_redhdr.cmsg_type = TPOPT_REDI_CALLMit getsockopt() auf der S-Seite wird auf die Daten des Accept-Sockets der L-Seite gewartet.
int getsockopt(int s, int level, int optname, char * optval, int* optlen);
optval ist ein Zeiger auf eine Strukur vom Typ cmsg_redhdr
level = SOL_TRANSPORT
optname = TPOPT_REDI_CALL
cmsg_redhdr.cmsg_len = sizeof(struct cmsg_redhdr)
cmsg_redhdr.cmsg_level = SOL_TRANSPORT
cmsg_redhdr.cmsg_type = TPOPT_REDI_CALLIn cmsg_redhdr.domain muss die Adressfamilie und in cmsg_redhdr.fd_server der fd des Sockets für den neuen Verbindungsendpunkt eingetragen werden.
Ist das Ereignis eingetroffen und abgeholt, wird die Verbindungsumgebung abschließend hergestellt und der Datenstopp für die Verbindung aufgehoben, d.h. Daten werden jetzt dem neuen Verbindungsendpunkt zugestellt.
Der Accept-Socket des ursprünglichen Endpunktes kann jetzt mit soc_close() geschlossen werden, auch die AF_ISO-Verbindung für die Handoff-Kommunikation kann geschlossen werden.