Exemplo n.º 1
0
extern int MoreUNIXCopyDescriptorToDescriptor(int source, int dest)
    // See comment in header.
{
    int		err;
    bool    done;
    char *  buffer;
    static const size_t kBufferSize = 64 * 1024;

    assert(source >= 0);
    assert(dest   >= 0);

    err = 0;
    buffer = (char *) malloc(kBufferSize);
    if (buffer == NULL) {
        err = ENOMEM;
    }

    if (err == 0) {
        done = false;
        do {
            size_t bytesRead;

            err = MoreUNIXRead(source, buffer, kBufferSize, &bytesRead);
            if (err == EPIPE) {
                done = true;
                err = 0;
            }
            if (err == 0) {
                err = MoreUNIXWrite(dest, buffer, bytesRead, NULL);
            }
        } while (err == 0 && !done);
    }

    free(buffer);

    return err;
}
Exemplo n.º 2
0
static int ConnectionRPC(
    ConnectionRef           conn, 
    const PacketHeader *    request, 
    PacketHeader *          reply, 
    size_t                  replySize
)
    // Perform an RPC (Remote Procedure Call) with the server.  That is, send 
    // the server a packet and wait for a reply.  You can only use this on 
    // connections that are not in listening mode.
    //
    // conn must be a valid connection
    //
    // packet must be a valid, ready-to-send, packet
    //
    // reply and replySize specify a buffer where the reply packet is placed;
    // reply size must not be NULL; replySize must not be less that the 
    // packet header size (sizeof(PacketHeader)); if the reply packet is bigger 
    // than replySize, the data that won't fit is discarded; you can detect this 
    // by looking at reply->fSize
    //
    // Returns an errno-style error code
    // On success, the buffer specified by reply and replySize will contain the 
    // reply packet; on error, the contents of that buffer is invalid; also, 
    // if this routine errors the connection is no longer useful (conn is still 
    // valid, but you can't use it to transmit any more data)
{
    int     err;
    
    assert(conn != NULL);
    assert(conn->fSockFD != -1);            // connection must not be shut down
    assert(conn->fSockCF == NULL);          // RPC and listening are mutually exclusive
                                            // because unsolicited packet might get mixed up 
                                            // with the reply

    assert(request != NULL);
    assert(request->fMagic == kPacketMagic);
    assert(request->fSize >= sizeof(PacketHeader));

    assert(reply != NULL);
    assert(replySize >= sizeof(PacketHeader));
    
    // Send the request.
    
    err = ConnectionSend(conn, request);
    
    // Read and validate the reply header.
    
    if (err == 0) {
        err = MoreUNIXRead(conn->fSockFD, reply, sizeof(PacketHeader), NULL);
    }
    if ( (err == 0) && (reply->fMagic != kPacketMagic) ) {
        fprintf(stderr, "ConnectionRPC: Bad magic (%.4s).\n", (char *) &reply->fMagic);
        err = EINVAL;
    }
    if ( (err == 0) && (reply->fType != kPacketTypeReply) ) {
        fprintf(stderr, "ConnectionRPC: Type wrong (%.4s).\n", (char *) &reply->fType);
        err = EINVAL;
    }
    if ( (err == 0) && (reply->fID != request->fID) ) {
        fprintf(stderr, "ConnectionRPC: ID mismatch (%" PRId32 ").\n", reply->fID);
        err = EINVAL;
    }
    if ( (err == 0) && ( (reply->fSize < sizeof(PacketHeader)) || (reply->fSize > kPacketMaximumSize) ) ) {
        fprintf(stderr, "ConnectionRPC: Bogus packet size (%" PRIu32 ").\n", reply->fSize);
        err = EINVAL;
    }

    // Read the packet payload that will fit in the reply buffer.
    
    if ( (err == 0) && (reply->fSize > sizeof(PacketHeader)) ) {
        uint32_t  payloadToRead;
        
        if (reply->fSize > replySize) {
            payloadToRead = replySize;
        } else {
            payloadToRead = reply->fSize;
        }
        payloadToRead -= sizeof(PacketHeader);
        
        err = MoreUNIXRead(conn->fSockFD, ((char *) reply) + sizeof(PacketHeader), payloadToRead, NULL);
    }

    // Discard any remaining packet payload that will fit in the reply buffer.
    // The addition check in the next line is necessary to avoid the undefined behaviour 
    // of malloc(0) in the dependent block.

    if ( (err == 0) && (reply->fSize > replySize) ) {
        uint32_t    payloadToJunk;
        void *      junkBuf;
        
        payloadToJunk = reply->fSize - replySize;
        
        junkBuf = malloc(payloadToJunk);
        if (junkBuf == NULL) {
            err = ENOMEM;
        }
        
        if (err == 0) { 
            err = MoreUNIXRead(conn->fSockFD, junkBuf, payloadToJunk, NULL);
        }
        
        free(junkBuf);
    }

    // Any errors cause us to immediately shut down our connection because we 
    // we're no longer sure of the state of the channel (that is, did we leave 
    // half a packet stuck in the pipe).
    
    if (err != 0) {
        ConnectionShutdown(conn);
    }
    
    return err;
}