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); }
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); }
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); } }
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; }
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); }
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); }
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 }