LogReader.cpp revision 501c373916e292764400dbae735f44b33378400f
10175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn/*
20175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn * Copyright (C) 2012-2013 The Android Open Source Project
30175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn *
40175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn * Licensed under the Apache License, Version 2.0 (the "License");
50175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn * you may not use this file except in compliance with the License.
60175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn * You may obtain a copy of the License at
70175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn *
80175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn *      http://www.apache.org/licenses/LICENSE-2.0
90175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn *
100175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn * Unless required by applicable law or agreed to in writing, software
110175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn * distributed under the License is distributed on an "AS IS" BASIS,
120175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn * See the License for the specific language governing permissions and
140175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn * limitations under the License.
150175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn */
160175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn
17fa3716b2501ccddc8e0cd30f6343692b8deb7639Mark Salyzyn#include <ctype.h>
180175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn#include <poll.h>
198daa9af02dc0e63ce220e3fa95bf5fe4d6b7a99aMark Salyzyn#include <sys/prctl.h>
200175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn#include <sys/socket.h>
215c77ad55d0cdee84cd45fd5d0d066f3c61d76ce6Mark Salyzyn#include <sys/types.h>
22dfc47e86858ea67c72f1df2fdb97094b8e8248f2Mark Salyzyn
230175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn#include <cutils/sockets.h>
24aeaaf81c2cc8366ac4f66eb3d2fc85f9b8194982Mark Salyzyn#include <private/android_logger.h>
250175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn
260175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn#include "FlushCommand.h"
272ad0bd0a9b594bbe2560b405b0008b7bc742cfcaMark Salyzyn#include "LogBuffer.h"
282ad0bd0a9b594bbe2560b405b0008b7bc742cfcaMark Salyzyn#include "LogBufferElement.h"
292ad0bd0a9b594bbe2560b405b0008b7bc742cfcaMark Salyzyn#include "LogReader.h"
302ad0bd0a9b594bbe2560b405b0008b7bc742cfcaMark Salyzyn#include "LogUtils.h"
310175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn
32501c373916e292764400dbae735f44b33378400fMark SalyzynLogReader::LogReader(LogBuffer* logbuf)
33501c373916e292764400dbae735f44b33378400fMark Salyzyn    : SocketListener(getLogSocket(), true), mLogbuf(*logbuf) {
347718778793b106498b931dd708a466cf3a6f6a0fMark Salyzyn}
350175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn
360175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn// When we are notified a new log entry is available, inform
370175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn// all of our listening sockets.
380175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzynvoid LogReader::notifyNewLog() {
390175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    FlushCommand command(*this);
400175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    runOnEachSocket(&command);
410175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn}
420175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn
43501c373916e292764400dbae735f44b33378400fMark Salyzynbool LogReader::onDataAvailable(SocketClient* cli) {
44e3aeeeeccc260c29ca5907a444f8d746bcc2f8a5Mark Salyzyn    static bool name_set;
45e3aeeeeccc260c29ca5907a444f8d746bcc2f8a5Mark Salyzyn    if (!name_set) {
46e3aeeeeccc260c29ca5907a444f8d746bcc2f8a5Mark Salyzyn        prctl(PR_SET_NAME, "logd.reader");
47e3aeeeeccc260c29ca5907a444f8d746bcc2f8a5Mark Salyzyn        name_set = true;
48e3aeeeeccc260c29ca5907a444f8d746bcc2f8a5Mark Salyzyn    }
498daa9af02dc0e63ce220e3fa95bf5fe4d6b7a99aMark Salyzyn
500175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    char buffer[255];
510175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn
520175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1);
530175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    if (len <= 0) {
540175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn        doSocketDelete(cli);
550175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn        return false;
560175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    }
570175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    buffer[len] = '\0';
580175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn
590175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    unsigned long tail = 0;
600175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    static const char _tail[] = " tail=";
61501c373916e292764400dbae735f44b33378400fMark Salyzyn    char* cp = strstr(buffer, _tail);
620175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    if (cp) {
630175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn        tail = atol(cp + sizeof(_tail) - 1);
640175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    }
650175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn
66fa3716b2501ccddc8e0cd30f6343692b8deb7639Mark Salyzyn    log_time start(log_time::EPOCH);
67fa3716b2501ccddc8e0cd30f6343692b8deb7639Mark Salyzyn    static const char _start[] = " start=";
68fa3716b2501ccddc8e0cd30f6343692b8deb7639Mark Salyzyn    cp = strstr(buffer, _start);
69fa3716b2501ccddc8e0cd30f6343692b8deb7639Mark Salyzyn    if (cp) {
70fa3716b2501ccddc8e0cd30f6343692b8deb7639Mark Salyzyn        // Parse errors will result in current time
71fa3716b2501ccddc8e0cd30f6343692b8deb7639Mark Salyzyn        start.strptime(cp + sizeof(_start) - 1, "%s.%q");
72fa3716b2501ccddc8e0cd30f6343692b8deb7639Mark Salyzyn    }
73fa3716b2501ccddc8e0cd30f6343692b8deb7639Mark Salyzyn
74b75cce0389748bea111ca62af623645117e12d9dMark Salyzyn    uint64_t timeout = 0;
75b75cce0389748bea111ca62af623645117e12d9dMark Salyzyn    static const char _timeout[] = " timeout=";
76b75cce0389748bea111ca62af623645117e12d9dMark Salyzyn    cp = strstr(buffer, _timeout);
77b75cce0389748bea111ca62af623645117e12d9dMark Salyzyn    if (cp) {
78b75cce0389748bea111ca62af623645117e12d9dMark Salyzyn        timeout = atol(cp + sizeof(_timeout) - 1) * NS_PER_SEC +
79b75cce0389748bea111ca62af623645117e12d9dMark Salyzyn                  log_time(CLOCK_REALTIME).nsec();
80b75cce0389748bea111ca62af623645117e12d9dMark Salyzyn    }
81b75cce0389748bea111ca62af623645117e12d9dMark Salyzyn
820175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    unsigned int logMask = -1;
830175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    static const char _logIds[] = " lids=";
840175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    cp = strstr(buffer, _logIds);
850175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    if (cp) {
860175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn        logMask = 0;
870175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn        cp += sizeof(_logIds) - 1;
880175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn        while (*cp && *cp != '\0') {
890175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn            int val = 0;
90fa3716b2501ccddc8e0cd30f6343692b8deb7639Mark Salyzyn            while (isdigit(*cp)) {
91fa3716b2501ccddc8e0cd30f6343692b8deb7639Mark Salyzyn                val = val * 10 + *cp - '0';
920175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn                ++cp;
930175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn            }
940175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn            logMask |= 1 << val;
950175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn            if (*cp != ',') {
960175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn                break;
970175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn            }
980175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn            ++cp;
990175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn        }
1000175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    }
1010175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn
1020175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    pid_t pid = 0;
1030175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    static const char _pid[] = " pid=";
1040175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    cp = strstr(buffer, _pid);
1050175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    if (cp) {
1060175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn        pid = atol(cp + sizeof(_pid) - 1);
1070175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    }
1080175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn
1090175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    bool nonBlock = false;
1100eeb06b932f185e10377e4494475d2cdd6adfa1bMark Salyzyn    if (!fastcmp<strncmp>(buffer, "dumpAndClose", 12)) {
111f669acb01880216b6c1d29fc226f2c3ec3a6368aMark Salyzyn        // Allow writer to get some cycles, and wait for pending notifications
112f669acb01880216b6c1d29fc226f2c3ec3a6368aMark Salyzyn        sched_yield();
113f669acb01880216b6c1d29fc226f2c3ec3a6368aMark Salyzyn        LogTimeEntry::lock();
114f669acb01880216b6c1d29fc226f2c3ec3a6368aMark Salyzyn        LogTimeEntry::unlock();
115f669acb01880216b6c1d29fc226f2c3ec3a6368aMark Salyzyn        sched_yield();
1160175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn        nonBlock = true;
1170175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    }
1180175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn
119f7c0f75275d0fde2d8b7614f1501f0ad0cd3a01cMark Salyzyn    uint64_t sequence = 1;
120f7c0f75275d0fde2d8b7614f1501f0ad0cd3a01cMark Salyzyn    // Convert realtime to sequence number
121f7c0f75275d0fde2d8b7614f1501f0ad0cd3a01cMark Salyzyn    if (start != log_time::EPOCH) {
122a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn        class LogFindStart {
123a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn            const pid_t mPid;
124a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn            const unsigned mLogMask;
125a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn            bool startTimeSet;
126501c373916e292764400dbae735f44b33378400fMark Salyzyn            log_time& start;
127501c373916e292764400dbae735f44b33378400fMark Salyzyn            uint64_t& sequence;
128f7c0f75275d0fde2d8b7614f1501f0ad0cd3a01cMark Salyzyn            uint64_t last;
129b6bee33182cedea49199eb2252b3f3b442899c6dMark Salyzyn            bool isMonotonic;
130a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn
131501c373916e292764400dbae735f44b33378400fMark Salyzyn           public:
132501c373916e292764400dbae735f44b33378400fMark Salyzyn            LogFindStart(unsigned logMask, pid_t pid, log_time& start,
133501c373916e292764400dbae735f44b33378400fMark Salyzyn                         uint64_t& sequence, bool isMonotonic)
134501c373916e292764400dbae735f44b33378400fMark Salyzyn                : mPid(pid),
135501c373916e292764400dbae735f44b33378400fMark Salyzyn                  mLogMask(logMask),
136501c373916e292764400dbae735f44b33378400fMark Salyzyn                  startTimeSet(false),
137501c373916e292764400dbae735f44b33378400fMark Salyzyn                  start(start),
138501c373916e292764400dbae735f44b33378400fMark Salyzyn                  sequence(sequence),
139501c373916e292764400dbae735f44b33378400fMark Salyzyn                  last(sequence),
140501c373916e292764400dbae735f44b33378400fMark Salyzyn                  isMonotonic(isMonotonic) {
1417718778793b106498b931dd708a466cf3a6f6a0fMark Salyzyn            }
142a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn
143501c373916e292764400dbae735f44b33378400fMark Salyzyn            static int callback(const LogBufferElement* element, void* obj) {
144501c373916e292764400dbae735f44b33378400fMark Salyzyn                LogFindStart* me = reinterpret_cast<LogFindStart*>(obj);
145501c373916e292764400dbae735f44b33378400fMark Salyzyn                if ((!me->mPid || (me->mPid == element->getPid())) &&
146501c373916e292764400dbae735f44b33378400fMark Salyzyn                    (me->mLogMask & (1 << element->getLogId()))) {
147a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn                    if (me->start == element->getRealTime()) {
148f7c0f75275d0fde2d8b7614f1501f0ad0cd3a01cMark Salyzyn                        me->sequence = element->getSequence();
149a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn                        me->startTimeSet = true;
150f7c0f75275d0fde2d8b7614f1501f0ad0cd3a01cMark Salyzyn                        return -1;
151b6bee33182cedea49199eb2252b3f3b442899c6dMark Salyzyn                    } else if (!me->isMonotonic ||
152501c373916e292764400dbae735f44b33378400fMark Salyzyn                               android::isMonotonic(element->getRealTime())) {
153a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn                        if (me->start < element->getRealTime()) {
154f7c0f75275d0fde2d8b7614f1501f0ad0cd3a01cMark Salyzyn                            me->sequence = me->last;
155a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn                            me->startTimeSet = true;
156f7c0f75275d0fde2d8b7614f1501f0ad0cd3a01cMark Salyzyn                            return -1;
157a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn                        }
158f7c0f75275d0fde2d8b7614f1501f0ad0cd3a01cMark Salyzyn                        me->last = element->getSequence();
159b6bee33182cedea49199eb2252b3f3b442899c6dMark Salyzyn                    } else {
160b6bee33182cedea49199eb2252b3f3b442899c6dMark Salyzyn                        me->last = element->getSequence();
161a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn                    }
162a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn                }
163a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn                return false;
164a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn            }
165a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn
166501c373916e292764400dbae735f44b33378400fMark Salyzyn            bool found() {
167501c373916e292764400dbae735f44b33378400fMark Salyzyn                return startTimeSet;
168501c373916e292764400dbae735f44b33378400fMark Salyzyn            }
169b6bee33182cedea49199eb2252b3f3b442899c6dMark Salyzyn        } logFindStart(logMask, pid, start, sequence,
170b6bee33182cedea49199eb2252b3f3b442899c6dMark Salyzyn                       logbuf().isMonotonic() && android::isMonotonic(start));
171a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn
172f7c0f75275d0fde2d8b7614f1501f0ad0cd3a01cMark Salyzyn        logbuf().flushTo(cli, sequence, FlushCommand::hasReadLogs(cli),
1738fa8896d2ed97eb274c62f0e386dabf2e2a82a45Mark Salyzyn                         FlushCommand::hasSecurityLogs(cli),
174a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn                         logFindStart.callback, &logFindStart);
175a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn
176a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn        if (!logFindStart.found()) {
177a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn            if (nonBlock) {
178a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn                doSocketDelete(cli);
179a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn                return false;
180a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn            }
181f7c0f75275d0fde2d8b7614f1501f0ad0cd3a01cMark Salyzyn            sequence = LogBufferElement::getCurrentSequence();
182a1c60cf80d0d1002576a6cf8aa395b295c6a272eMark Salyzyn        }
183fa3716b2501ccddc8e0cd30f6343692b8deb7639Mark Salyzyn    }
184fa3716b2501ccddc8e0cd30f6343692b8deb7639Mark Salyzyn
185b75cce0389748bea111ca62af623645117e12d9dMark Salyzyn    FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence, timeout);
1865c77ad55d0cdee84cd45fd5d0d066f3c61d76ce6Mark Salyzyn
1875c77ad55d0cdee84cd45fd5d0d066f3c61d76ce6Mark Salyzyn    // Set acceptable upper limit to wait for slow reader processing b/27242723
1885c77ad55d0cdee84cd45fd5d0d066f3c61d76ce6Mark Salyzyn    struct timeval t = { LOGD_SNDTIMEO, 0 };
189501c373916e292764400dbae735f44b33378400fMark Salyzyn    setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char*)&t,
190501c373916e292764400dbae735f44b33378400fMark Salyzyn               sizeof(t));
1915c77ad55d0cdee84cd45fd5d0d066f3c61d76ce6Mark Salyzyn
1920175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    command.runSocketCommand(cli);
1930175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    return true;
1940175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn}
1950175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn
196501c373916e292764400dbae735f44b33378400fMark Salyzynvoid LogReader::doSocketDelete(SocketClient* cli) {
197501c373916e292764400dbae735f44b33378400fMark Salyzyn    LastLogTimes& times = mLogbuf.mTimes;
1980175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    LogTimeEntry::lock();
1990175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    LastLogTimes::iterator it = times.begin();
200501c373916e292764400dbae735f44b33378400fMark Salyzyn    while (it != times.end()) {
201501c373916e292764400dbae735f44b33378400fMark Salyzyn        LogTimeEntry* entry = (*it);
2020175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn        if (entry->mClient == cli) {
2030175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn            times.erase(it);
2040175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn            entry->release_Locked();
2050175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn            break;
2060175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn        }
2070175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn        it++;
2080175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    }
2090175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn    LogTimeEntry::unlock();
2100175b0747a1f55329109e84c9a1322dcb95e2848Mark Salyzyn}
211dfc47e86858ea67c72f1df2fdb97094b8e8248f2Mark Salyzyn
212dfc47e86858ea67c72f1df2fdb97094b8e8248f2Mark Salyzynint LogReader::getLogSocket() {
213dfc47e86858ea67c72f1df2fdb97094b8e8248f2Mark Salyzyn    static const char socketName[] = "logdr";
214dfc47e86858ea67c72f1df2fdb97094b8e8248f2Mark Salyzyn    int sock = android_get_control_socket(socketName);
215dfc47e86858ea67c72f1df2fdb97094b8e8248f2Mark Salyzyn
216dfc47e86858ea67c72f1df2fdb97094b8e8248f2Mark Salyzyn    if (sock < 0) {
217501c373916e292764400dbae735f44b33378400fMark Salyzyn        sock = socket_local_server(
218501c373916e292764400dbae735f44b33378400fMark Salyzyn            socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET);
219dfc47e86858ea67c72f1df2fdb97094b8e8248f2Mark Salyzyn    }
220dfc47e86858ea67c72f1df2fdb97094b8e8248f2Mark Salyzyn
221dfc47e86858ea67c72f1df2fdb97094b8e8248f2Mark Salyzyn    return sock;
222dfc47e86858ea67c72f1df2fdb97094b8e8248f2Mark Salyzyn}
223