Example #1
0
// Writes data to the socket of the specified connection
func sendOut(user *Admin, query map[string]interface{}) error {
	enc := bencode.NewEncoder()
	enc.Encode(query)
	_, err := io.WriteString(user.Conn, string(enc.Bytes))
	if err != nil {
		return err
	}
	return nil
}
Example #2
0
func SendCmd(user *Admin, cmd string, args map[string]interface{}) (response map[string]interface{}, err error) {
	query := make(map[string]interface{})
	enc := bencode.NewEncoder()

	// Generate a unique transaction ID for this request.
	// This tells Reader which channel to send the data back to us on.
	txid := strconv.FormatInt(rand.Int63(), 10) //randInt(10, 15)
	query["txid"] = txid

	// Check if we need to use authentication for this command.
	if cmd == "ping" || cmd == "cookie" {
		query["q"] = cmd
	} else {

		//Request a cookie
		cookie, err := ReqCookie(user)
		if err != nil {
			return nil, err
		}

		query["q"] = "auth"
		query["aq"] = cmd
		query["cookie"] = cookie
		if args != nil {
			query["args"] = args
		}
		//Generate the first hash we need
		query["hash"] = sha256hash(user.Password + cookie)

		//Encode the query and get the final hash
		enc.Encode(query)
		data := string(enc.Bytes)
		query["hash"] = sha256hash(data)
	}

	//Re-encode the query with the new hash
	enc = bencode.NewEncoder()
	enc.Encode(query)

	// If we are telling cjdns to exit, then we will not get a response, so there is no need to wait
	if cmd != "Core_exit" {
		//create the channel to receive data back on
		rChan := make(chan map[string]interface{}, 1) // use buffered channel to avoid blocking reader.

		user.Mu.Lock()
		user.Channels[txid] = rChan
		user.Mu.Unlock()

		// remove channel from map no matter how this function exits.
		defer func() {
			user.Mu.Lock()
			delete(user.Channels, txid)
			user.Mu.Unlock()
		}()

		//Send the query
		_, err = io.WriteString(user.Conn, string(enc.Bytes))
		if err != nil {
			return nil, err
		}

		output, ok := <-rChan
		if !ok {
			return nil, fmt.Errorf("Socket closed")
		}

		// If an error field exists, and we have an error, return it
		if _, ok := response["error"]; ok {
			if response["error"] != "none" {
				err = fmt.Errorf(response["error"].(string))
				return
			}
		}
		return output, nil
	}
	//Send the query
	_, err = io.WriteString(user.Conn, string(enc.Bytes))
	if err != nil {
		return nil, err
	}
	return make(map[string]interface{}), nil
}