[C]Lokale Variable in Verbindung mit bind(2) in Funkion nutzen?

Herakles

Profifragensteller
Moin!

Anfängerfrage: Heftet ein bind(2) ein lokales struct sockaddr_in an einen global definierten Socket auch über die Abarbeitung der Funktion hinaus oder nicht? Oder einfacher gefragt: Ist der folgende Code gültig?

Code:
void create_localhost_socket_udp_server( void ) {
   struct sockaddr_in servaddr;
   
   memset( &servaddr, 0, sizeof(struct sockaddr_in) );
   global.local_socket_I = socket( AF_INET, SOCK_DGRAM, 0 );
   servaddr.sin_family = AF_INET;
   servaddr.sin_addr.s_addr = htonl("127.0.0.1");
   servaddr.sin_port = htons(12345);
   bind( global.local_socket_I, (struct sockaddr *)&servaddr, sizeof(servaddr) );
}

...oder müsste auch das genutzte struct sockaddr_in servaddr global definiert werden?

Grüße
Herakles
 
Das müsste so ok sein. Das ist nur zur Initialisierung und wird nicht mehr benutzerseitig gebraucht.
 
Wozu denn einfach glauben (auch wenn die beiden völlig richtig liegen), wir haben doch schließlich quelloffene Systeme vor uns. ;)

In meinem Fall ist es OpenBSD, die Unterschiede sind aber gering. Hier und da andere Datei, andere Definition...

Wie du bereits in der Schreibweise bind(2) festgestellt hast, handelt es sich um einen Systemaufruf. Schönen Userland-Quelltext gibts daher keinen, lediglich einen Systemaufruf-Wrapper. Das ist dann meistens Assembler-Code.

Stark gekürzte /usr/src/lib/libc/sys/Makefile.inc:
Code:
# modules with default implementations on all architectures, unless overriden
# below:
ASM= bind.o

${ASM}: ${LIBCSRCDIR}/arch/${MACHINE_CPU}/SYS.h /usr/include/sys/syscall.h
  @echo creating ${.TARGET}
  @printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' | \
  ${COMPILE.S} ${CFLAGS:M-[ID]*} ${AINC} -x assembler-with-cpp - \
  -o ${.TARGET}.o
  @${LD} -x -r ${.TARGET}.o -o ${.TARGET}
  @rm -f ${.TARGET}.o

Das sieht äußerst wüst aus. Was aber effektiv passiert ist, dass je nach System die passende Nummer des Systemaufrufs an den Kernel übergeben wird. Bei der Intel-Architektur (zumindest i386) per Soft-Interrupt.

Sieht dann ganz grob wie folgt aus:
Code:
movl $(SYS_bind),%eax;
int $0x80;

mit der Definition von SYS_bind in /usr/include/sys/syscall.h:
Code:
#define SYS_bind  104

Die Nummer des jeweiligen Systemaufrufs verrät der Kernel in /usr/src/sys/kern/syscalls.master, aus der auch die gerade genannte Include-Datei generiert wird:
Code:
104     STD             { int sys_bind(int s, const struct sockaddr *name, \
                            socklen_t namelen); }
Und da findet sich dann auch schon die Signatur des Kernel-Codes, mit dem der Systemaufruf verarbeitet wird: sys_bind

Der Kernel-Code für bind befindet sich in /usr/src/sys/kern/uipc_syscalls.c. Stark gekürzte Fassung:
Code:
int
sys_bind(struct proc *p, void *v, register_t *retval)
{
  struct sys_bind_args /* {
    syscallarg(int) s;
    syscallarg(const struct sockaddr *) name;
    syscallarg(socklen_t) namelen;
  } */ *uap = v;

  error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen), MT_SONAME);
  if (error == 0) {
    error = sobind(fp->f_data, nam, p);
    m_freem(nam);
  }

  return (error);
}

Und sockargs ebenso (auch SEHR stark gekürzt):
Code:
int
sockargs(struct mbuf **mp, const void *buf, size_t buflen, int type)
{
  struct mbuf *m;

  /* Allocate an mbuf to hold the arguments. */
  m = m_get(M_WAIT, type);
  m->m_len = buflen;
  copyin(buf, mtod(m, caddr_t), buflen);
  *mp = m;
  return (0);
}

Der copyin-Aufruf macht nichts weiter, als die Daten aus dem Userland in den Kernelspace zu kopieren. Und selbst dort verweilt er nicht lange. Der mbuf-Speicher wird gleich nach dem sobind-Aufruf wieder freigegeben.

Also gaaanz lange Antwort auf die kurze Frage, ob der Speicher noch gebraucht wird: Nein. ;)


Mein Post soll daher auch eher als Grundlage dienen, wenn du (oder jemand anderes) gerne wissen würde, was eigentlich bei Systemaufrufen passiert. Ich hab mir damals einen Wolf gesucht.
 
Ich wollte gerade bind(2) empfehlen. Aber die Manual page ist nicht besonders auskunftsfreudig.
 
Zurück
Oben