示例#1
0
void PipeDelete (
  struct PipeS ** const pipeP
)
{
  struct PipeS * pipe = *pipeP;
  if (unlikely(pipe == NULL)) return;
  SysCloseSocket (MQ_CONTEXT_S, __func__, MQ_YES, (MQ_IS_CLIENT(MQ_CONTEXT_S) ?  &pipe->config->socks[0] : &pipe->config->socks[1]));
  MqSysFree(*pipeP);
}
示例#2
0
void
pIoCloseSocket (
  struct MqIoS * const io,
  MQ_CST const caller
)
{
  if (unlikely(io == NULL)) return;
  pIoShutdown (io);
  SysCloseSocket (io->context, caller, MQ_YES, io->sockP);
}
示例#3
0
void
GenericDelete (
  struct GenericS ** const genericP
)
{
  if (unlikely(genericP == NULL || *genericP == NULL)) {
    return;
  } else {
    SysCloseSocket (MQ_ERROR_IGNORE, __func__, MQ_YES, &(*genericP)->sock);
    MqSysFree (*genericP);
  }
}
示例#4
0
SYS_SOCKET BSckDetach(BSOCK_HANDLE hBSock, int iCloseSocket)
{
    BuffSocketData *pBSD = (BuffSocketData *) hBSock;
    SYS_SOCKET SockFD = SYS_INVALID_SOCKET;

    if (pBSD != NULL) {
        SockFD = pBSD->SockFD;
        BSOCK_FREE(pBSD);
        SysFree(pBSD->pszBuffer);
        SysFree(pBSD);
        if (iCloseSocket) {
            SysCloseSocket(SockFD);
            return SYS_INVALID_SOCKET;
        }
    }

    return SockFD;
}
示例#5
0
enum MqErrorE
GenericServer (
  struct GenericS * const generiC,	///< the current generic handle
  struct sockaddr * const sockaddr,	///< the address package
  socklen_t const sockaddrlen,		///< the length of the address
  struct MqBufferLS * const alfa
) {
  struct MqS * const context = MQ_CONTEXT_S;
  MQ_SOCK child_sock;
  struct sockaddr mysockaddr; 
  socklen_t mysockaddrlen;
  // this is just a flag
  struct MqIdS id;

  // the parent server should "forget" his child's
  // server / child dependency management is done by libmsgque
  if (	    context->config.startAs == MQ_START_SPAWN
#if defined(HAVE_FORK)
	||  context->config.startAs == MQ_START_FORK
#endif
     ) {
    // do not create a "defunc" process
    MqErrorCheck (SysIgnorSIGCHLD(context));
  }

  // 1. create socket
  MqErrorCheck (GenericBind (generiC, sockaddr, sockaddrlen));

  // 2. listen on port
  MqErrorCheck (SysListen (context, generiC->sock, 128));
  do {
    id.type = MQ_ID_UNUSED;
    mysockaddrlen = sizeof(mysockaddr);
    // 3. accept incomming call
    MqErrorCheck (SysAccept (context, generiC->sock, &mysockaddr, &mysockaddrlen, &child_sock));
    // select: how to start the new task
    switch (context->config.startAs) {
      case MQ_START_FORK: {
#if defined(HAVE_FORK)
	MqErrorCheck (pIoStartServer(context->link.io,MQ_START_SERVER_AS_INLINE_FORK, &child_sock, NULL, MqBufferLDup(alfa), &id));
#endif
	break;
      }
      case MQ_START_THREAD: {
#if defined(MQ_HAS_THREAD)
	MqErrorCheck (pIoStartServer(context->link.io,MQ_START_SERVER_AS_THREAD, &child_sock, NULL, MqBufferLDup(alfa), &id));
	// keep the "child_sock" open, because it's still the same process
#endif
	break;
      }
      case MQ_START_SPAWN: {
	MqErrorCheck (pIoStartServer(context->link.io,MQ_START_SERVER_AS_SPAWN, &child_sock, NULL, MqBufferLDup(alfa), &id));
	break;
      }
      case MQ_START_DEFAULT: {
	// server setup without "--fork,--thread or --spawn", this is just a singel request server.
	// The server will shutdown on the end of the link.
	break;
      }
    }

  // for a NON --fork/--thread/--spawn server the 'id.val' will allways be '0' -> continue
  // for a --fork/--thread/--spawn parent the 'id.val' will be set by pIoStartServer to something else 
  //   than 0 -> loop
  // for a --fork/--thread/--spawn child the 'id.val' will be '0' -> continue
  } while (
	(id.type == MQ_ID_PROCESS && id.val.process != 0) 
#if defined(MQ_HAS_THREAD)
    ||	(id.type == MQ_ID_THREAD  && id.val.thread  != 0UL)	   
#endif
  );

  // fork child (pid=0) close parent socket
  MqErrorCheck (SysCloseSocket (context, __func__, MQ_NO, &generiC->sock));
  generiC->sock = child_sock;

  // 3. save socket pointer and listen on socket events
  pIoEventAdd(generiC->io, &generiC->sock);

  // 4. the fork-server should "allow" the SIGCHLD
  if (	    context->config.startAs == MQ_START_SPAWN
#if defined(HAVE_FORK)
	||  context->config.startAs == MQ_START_FORK
#endif
     ) {
    /*
     * TCL complain if SIGCHLD is ignored 
     * -> additional information from TCL source-code:
     * This changeup in message suggested by Mark Diekhans
     * to remind people that ECHILD errors can occur on
     * some systems if SIGCHLD isn't in its default state.
     */
    MqErrorCheck (SysAllowSIGCHLD(context));
  }

  // 5, finish
error:
  return MqErrorStack (context);
}
示例#6
0
enum MqErrorE
pIoStartServer (
  struct MqIoS * const io,
  enum IoStartServerE startType,
  MQ_SOCK * sockP,
  struct MqBufferLS ** alfaP,
  struct MqBufferLS * alfa2, // if alfaP!=NULL than alfa2 will be set by alfaP
  struct MqIdS * idP
) {
  struct MqS * const context = io->context;
#if defined(MQ_HAS_THREAD) || defined(HAVE_FORK)
  struct MqFactoryS factory = MqFactoryS_NULL;
  struct MqBufferLS * alfa1 = NULL;
  int start_as_pipe = 0;
#endif
#if defined(MQ_HAS_THREAD)
# if defined(HAVE_PTHREAD)
    int thread_status = PTHREAD_CREATE_DETACHED;
# elif defined(MQ_IS_WIN32)
    int thread_status = 0;
# endif
#endif

  MQ_CST  name = NULL;

  // alfa is now owned by "pIoStartServer"
  if (alfaP != NULL) {
    alfa1 = *alfaP;
    *alfaP = NULL;
  }

/*
I0
printULS(alfa1)
printLP(alfa1->data)
printLP(alfa1->cur)
*/

  // select the code
rescan:
  switch (startType) {
    case MQ_START_SERVER_AS_PIPE: {
	start_as_pipe = 1;
//printLC("MQ_START_SERVER_AS_PIPE:")
	// case 2: this is used if the function is called from MqLinkCreate. The
	// context->alfa argument has the startup arguments of the MQ_IO_PIPE server.
	// MQ_IO_TCP and MQ_IO_UDS is ignored and it is an error if context->alfa is
	// available too.
	if (io->config->com != MQ_IO_PIPE) {
	  // for non "PIPE" io the "alfa" have to be empty
	  if (alfa1 != NULL) {
	    MqBufferLDelete(&alfa1);
	    return MqErrorDbV2 (context, MQ_ERROR_CAN_NOT_START_NON_PIPE_SERVER, pIoLogCom(io->config->com));
	  }
	  // for non "PIPE" io we have nothing to do
	  return MQ_OK;
	}
	if (alfa1 == NULL) {
	  return MqErrorDb2 (context, MQ_ERROR_CAN_NOT_START_CLIENT);
	}
	// setup alfa1/2
	pBufferLSplitAlfa(&alfa1, &alfa2);
	// get the socket from the pipe
	sockP = PipeGetServerSocket(io->iocom.pipeSP);
	// get the id storage
	idP = &io->id;
	// this is the first entry in alfa1
	name = alfa1->data[0]->cur.C;
//printLC(name)

	// check if we use the "WORKER" keyword
	if (context->link.isWORKER) {
	  // replace "WORKER" with "MqInitBuf" data
	  name = MqInitBuf->data[0]->cur.C;
	  // replace "WORKER" itself on position "0"
	  MqErrorCheck (MqBufferLDeleteItem (context, alfa1, 0, 1, MQ_YES));
	  // add startup entry function
	  factory = context->setup.Factory;
	} else {
	  // does we use MqMainSelector and is the first entry in alfa1 found?
	  if (MqFactorySelector) factory = MqFactorySelector(name);

	  // if yes then use MqMainToolName (if available)
	  // > atool split ... @ cut ... @ join ...
	  // name is "cut" and next line will replace the name with "atool"
	  name = ( factory.Create.fCall && MqInitBuf ? MqInitBuf->data[0]->cur.C : name );
	}

//printLC(name)
//printLP(fFactory)

	if (factory.Create.fCall) {
#if defined(HAVE_FORK)
	  // continue with "fork"
	  if (context->config.ignoreFork == MQ_NO && (
		context->config.startAs == MQ_START_DEFAULT || 
		context->config.startAs == MQ_START_FORK)) {
//printLC("fork")
	    startType = MQ_START_SERVER_AS_FORK;
	    // if isWORKER than the startup is like a "GenericServer" and not like a "pipe"
	    if (context->link.isWORKER == MQ_YES) {
	      MqBufferLAppend(alfa1, MqBufferCreateC(MQ_ERROR_PANIC, name), 0);
	    }
	    goto rescan;
	  }
#endif
#if defined(MQ_HAS_THREAD)
	  // continue with "thread"
	  if (context->config.ignoreThread == MQ_NO && (
		context->config.startAs == MQ_START_DEFAULT || 
		context->config.startAs == MQ_START_THREAD)) {
//printLC("thread")
	    startType = MQ_START_SERVER_AS_THREAD;
	    // if isWORKER than the startup is like a "GenericServer" and not like a "pipe"
	    if (context->link.isWORKER == MQ_YES) {
	      MqBufferLAppend(alfa1, MqBufferCreateC(MQ_ERROR_PANIC, name), 0);
	    }
#if defined(HAVE_PTHREAD)
	    thread_status = PTHREAD_CREATE_JOINABLE;
#endif
	    goto rescan;
	  }
#endif
	}
	// continue with "spawn" (works allways)
	if (context->config.ignoreSpawn == MQ_YES) {
	  MqErrorDbV2(context, MQ_ERROR_CAN_NOT_START_NON_PIPE_SERVER,(name == NULL ? "unknown" : name));
	}
//printLC("spawn")
	startType = MQ_START_SERVER_AS_SPAWN;
	// only SPAWN need all arguments from MqInitBuf
	if (factory.Create.fCall != NULL) {
	  MqBufferLAppendL(alfa1, MqInitBuf, 0);
	}

	goto rescan;
      }
      break;
#if defined(MQ_HAS_THREAD)
    case MQ_START_SERVER_AS_THREAD: {
//printLC("MQ_START_SERVER_AS_THREAD:")
	// copy the configuration from the "PARENT" server
	if (!start_as_pipe) {
	  factory = context->setup.Factory;
	}

	// MqMainToolName set in "sMqCheckArg" or at application main startup
	if (name == NULL) {
	  if (MqInitBuf == NULL) {
	    return MqErrorDb2(context, MQ_ERROR_NO_INIT);
	  } else {
	    name = MqInitBuf->data[0]->cur.C;
	  }
	}

	// empty alfa1 (GenericServer) starup -> init with MqInitBuf data
	if (alfa1 == NULL) {
	  alfa1 = MqBufferLCreate(20);
	  MqBufferLAppendC(alfa1, name);
	}

	// fill arg with system-arguments
	sIoFillArgvU(io,*sockP,alfa1,"--thread");
	// start the server

/*
I2
MqBufferLLogS(context, alfa1, "alfa1");
MqBufferLLogS(context, alfa2, "alfa2");
*/

	MqErrorCheck (SysServerThread (context, factory, &alfa1, &alfa2, name, thread_status, idP));
      }
      break;
#endif /* MQ_HAS_THREAD */
#if defined(HAVE_FORK)
    case MQ_START_SERVER_AS_FORK: {
//printLC("MQ_START_SERVER_AS_FORK:")
	// copy the configuration from the "PARENT" server
	if (!start_as_pipe) {
	  factory = context->setup.Factory;
	}

	// MqMainToolName set in "sMqCheckArg" or at application main startup
	if (name == NULL) {
	  if (MqInitBuf == NULL) {
	    return MqErrorDb2(context, MQ_ERROR_NO_INIT);
	  } else {
	    name = MqInitBuf->data[0]->cur.C;
	  }
	}

	// empty alfa1 (GenericServer) starup -> init with MqInitBuf data
	if (alfa1 == NULL) {
	  alfa1 = MqBufferLCreate(20);
	  MqBufferLAppendC(alfa1, name);
	}

	// fill arg with system-arguments
	sIoFillArgvU(io,*sockP,alfa1,"--fork");

	// start the server
	MqErrorCheck (SysServerFork (context, factory, &alfa1, &alfa2, name, idP));
	// cleanup socket of the child
	MqErrorCheck(SysCloseSocket (context, __func__, MQ_NO, sockP));
      }
      break;
#endif   /* HAVE_FORK */
    case MQ_START_SERVER_AS_SPAWN: {
//printLC("MQ_START_SERVER_AS_SPAWN:")
	char **argV, **arg;
	// add 20 item's as additional space
	argV = arg = (char **) MqSysMalloc (context, sizeof(*alfa1) * (
	    (alfa1 != NULL ? alfa1->cursize : 0) + (alfa2 ? alfa2->cursize : 0) + 20 
	));

	// init main
	if (name == NULL) {
	  if (MqInitBuf == NULL) {
	    return MqErrorDb2(context, MQ_ERROR_NO_INIT);
	  } else {
	    name = MqInitBuf->data[0]->cur.C;
	  }
	}

	// empty alfa1 (GenericServer) starup -> init with MqInitBuf data
	if (alfa1 == NULL) {
          int i;
	  for (i=0; i<MqInitBuf->cursize; i++) {
	    *arg++ = mq_strdup(MqInitBuf->data[i]->cur.C);
	  }
	} else {
	  struct MqBufferS **start, **end;

	  // copy everything befor the first MQ_ALFA
	  start = alfa1->data;
	  end = start+alfa1->cursize;
	  for (; start < end; start++) {
	    *arg++ = mq_strdup((*start)->cur.C);
	  }
	}

	// fill arg with system-arguments
	sIoFillArgvC(io, alfa2, *sockP, arg, "--spawn");
	// start the server

/*
        {
int i;
char ** xarg = argV;
printLC(name)
for (i=0; *xarg != NULL; xarg++, i++) {
  MqDLogX (context, __func__, 0, "alfa1[%2i]=%s\n",i, *xarg);
}
        }
*/

	MqErrorCheck (SysServerSpawn (context, argV, name, idP));

	// cleanup array's
	SysFreeArgvArray (&argV);
	// cleanup socket of the child
	MqErrorCheck(SysCloseSocket (context, __func__, MQ_NO, sockP));
      }
      break;
#if defined(HAVE_FORK)
    case MQ_START_SERVER_AS_INLINE_FORK: {
//printLC("MQ_START_SERVER_AS_INLINE_FORK:")
	if (name == NULL && MqInitBuf != NULL) {
	  name = MqInitBuf->data[0]->cur.C;
	} else {
	  return MqErrorDb2(context, MQ_ERROR_NO_INIT);
	}
	// case: the function GenericServer is listen on a "tcl" or "uds" connection
	// and start for every incomming connection a new process with "fork". !no!
	// initialization have to be done because we reuse the current state.
	MqErrorCheck (SysFork (context, idP));
	// if pid != 0 -> this is the parent just continue with default "client" code
	if ((*idP).val.process == 0) {
	  // pid = 0 -> this is the fork child
	  context->statusIs = (enum MqStatusIsE) (context->statusIs | MQ_STATUS_IS_FORK);
	  // we don't need to cleanup argv1/2 because the INLINE_FORK is done
	  // with an empty "alfa"
	  return MQ_OK;
	}
	// cleanup socket of the child
	MqErrorCheck(SysCloseSocket (context, __func__, MQ_NO, sockP));
      }
      break;
#endif   /* HAVE_FORK */
  }

  // ok 2: inform the user
  if (unlikely(context != NULL && context->config.debug >= 4)) {
    MQ_STRB buf[50];
    // !attention "name" can be "alfa1[0]"
    MqDLogX(context,__func__,4,"finish start server '%s' as '%s' with ID '%s'\n",
		name, pIoLogStartType(startType), pIoLogId(buf,50,*idP));
  }

  // cleanup alfa1/2
  MqBufferLDelete (&alfa1);
  MqBufferLDelete (&alfa2);

error:
  return MqErrorStack (context);
}
示例#7
0
enum MqErrorE
SysSocketPair (
  struct MqS * const context,	    ///< [in] handle error
  int socks[]				    ///< [out] the result from socketpair
) {
#if defined(HAVE_SOCKETPAIR)
  int oldflags;
  sSysSetErrorNum(0);
  if (unlikely (socketpair (AF_UNIX, SOCK_STREAM, 0, socks) == -1)) {
    return sSysMqErrorMsg (context, __func__, "socketpair");
  }

  if (unlikely ((oldflags = fcntl (socks[0], F_GETFD, 0)) == -1)) {
    return sSysMqErrorMsg (context, __func__, "fcntl F_GETFD");
  }
  oldflags |= FD_CLOEXEC;
  if (unlikely (fcntl (socks[0], F_SETFD, oldflags) == -1)) {
    return sSysMqErrorMsg (context, __func__, "fcntl F_SETFD");
  }

  return MQ_OK;
#else
/* socketpair.c
 * Copyright 2007 by Nathan C. Myers <*****@*****.**>; all rights reserved.
 * This code is Free Software.  It may be copied freely, in original or 
 * modified form, subject only to the restrictions that (1) the author is
 * relieved from all responsibilities for any use for any purpose, and (2)
 * this copyright notice must be retained, unchanged, in its entirety.  If
 * for any reason the author might be held responsible for any consequences
 * of copying or use, license is withheld.  
 */

/* dumb_socketpair:
 *   If make_overlapped is nonzero, both sockets created will be usable for
 *   "overlapped" operations via WSASend etc.  If make_overlapped is zero,
 *   socks[0] (only) will be usable with regular ReadFile etc., and thus 
 *   suitable for use as stdin or stdout of a child process.  Note that the
 *   sockets must be closed with closesocket() regardless.
 */
    struct sockaddr_in addr;
    MQ_SOCK listener;
    socklen_t addrlen = sizeof(addr);

    socks[0] = socks[1] = INVALID_SOCKET;
    MqErrorCheck (SysSocket(context,AF_INET,SOCK_STREAM,0,&listener));

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(0x7f000001);
    addr.sin_port = 0;

    MqErrorCheck (SysBind(context,listener, (const struct sockaddr*) &addr, sizeof(addr)));
    MqErrorCheck (SysGetSockName(context, listener, (struct sockaddr*) &addr, &addrlen));

    do {
	MqErrorCheck (SysListen(context,listener,1));
	MqErrorCheck (SysSocket(context,AF_INET,SOCK_STREAM,0,&socks[0]));
	MqErrorCheck (SysConnect(context,socks[0],(struct sockaddr*const) &addr, sizeof(addr),1));
	MqErrorCheck (SysAccept(context,listener,NULL,NULL,&socks[1]));
	MqErrorCheck (SysCloseSocket(context,__func__,MQ_NO,&listener));
        return MQ_OK;
    } while (0);
    return sSysMqErrorMsg (context, __func__, "socketpair");

error:
  MqErrorCheck (SysCloseSocket(MQ_ERROR_IGNORE,__func__,MQ_NO,&listener));
  return MqErrorStack (context);
#endif
}